ngày cuối cùng của tháng tính toán


144

Tôi đang gặp vấn đề với việc tính toán khi nào Ngày cuối cùng của tháng tiếp theo dành cho một thông báo dự kiến ​​sẽ được gửi.

Đây là mã của tôi:

RecurrenceFrequency recurrenceFrequency = notification.getRecurrenceFrequency();
Calendar nextNotifTime = Calendar.getInstance();

Đây là dòng gây ra vấn đề tôi tin:

nextNotifTime.add(recurrenceFrequency.getRecurrencePeriod(), 
                  recurrenceFrequency.getRecurrenceOffset());

Làm cách nào tôi có thể sử dụng Lịch để đặt đúng ngày cuối cùng của tháng tiếp theo cho thông báo?


1
Đặt nó vào ngày đầu tiên của tháng tiếp theo và sau đó quay lại một ngày.
Hóa đơn

Một SSCCE sẽ làm cho nó dễ dàng hơn để trả lời câu hỏi này. Vấn đề gì bạn thực sự nhìn thấy?
DNA

Câu trả lời:


347
Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH);

Điều này trả về tối đa thực tế cho tháng hiện tại. Ví dụ, bây giờ là tháng hai năm nhuận, vì vậy nó trả về 29 như int.


cảm ơn, tôi cần phải đạt được mức tối đa cho tháng tiếp theo, tuy nhiên, nó vẫn phải hoạt động để nó có thể là ngày đầu tiên của tháng, vì phần đó hoạt động ngay bây giờ. cảm ơn một lần nữa vì thời gian và công sức của bạn
OakvilleWork

4
Nó không phải là một vấn đề để có được ActualMaximumcho mỗi ngày. Chỉ cần cuộn lịch đến ngày yêu cầu trước khi gọi getActualMaximum. Ngày đầu tiên có thể được lấy bởigetActualMinimum()
AlexR

ok cảm ơn rất nhiều Alex, vì vậy nếu tôi muốn đưa ví dụ về một tháng tới và tìm ra getActualMaximum cho tháng đó thì tôi sẽ làm như thế nào ?? chúc mừng
OakvilleWork

đây có phải là Alex không? nextNotifTime.roll (Lịch.MONTH, đúng); nextNotifTime.getActualMaximum (Lịch.DAY_OF_MONTH);
OakvilleWork

Ngoài ra, tôi đặt thời gian ngày sẵn sàng sau này: nextNotification.setReadyDateTime(nextNotifTime.getTime()); do đó tôi không nên làm điều này thay vào đó : nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork

61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Sử dụng java.timethư viện được tích hợp trong Java 8, bạn có thể sử dụng TemporalAdjustergiao diện. Chúng tôi tìm thấy một triển khai đã sẵn sàng để sử dụng trong TemporalAdjusterslớp tiện ích : lastDayOfMonth.

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

LocalDate now = LocalDate.now(); //2015-11-23
LocalDate lastDay = now.with(TemporalAdjusters.lastDayOfMonth()); //2015-11-30

Nếu bạn cần thêm thông tin về thời gian, bạn có thể sử dụng bất kỳ thông tin có sẵn nào LocalDateđể LocalDateTimechuyển đổi như

lastDay.atStartOfDay(); //2015-11-30T00:00

Câu trả lời tốt. Nhưng phần cuối cùng là yếu, đề nghị sử dụng LocalDateTime. Lớp đó thiếu bất kỳ khái niệm nào về múi giờ hoặc offset-từ-UTC. Vì vậy, nó không thể xác định khi một ngày cụ thể ở một nơi cụ thể thực sự bắt đầu. Lớp học đó chỉ hoạt động trong những ngày 24 giờ chung chung, không phải ngày thực tế. Đối với ngày thực, chỉ định múi giờ : ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Một số ngày ở một số nơi có thể bắt đầu vào một thời điểm khác nhau, chẳng hạn như 01:00, vì những bất thường như Giờ tiết kiệm ánh sáng ban ngày (DST).
Basil Bourque

35

Và để lấy ngày cuối cùng làm đối tượng Ngày:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));

Date lastDayOfMonth = cal.getTime();

22

Bạn có thể đặt lịch vào đầu tháng sau và trừ đi một ngày.

Calendar nextNotifTime = Calendar.getInstance();
nextNotifTime.add(Calendar.MONTH, 1);
nextNotifTime.set(Calendar.DATE, 1);
nextNotifTime.add(Calendar.DATE, -1);

Sau khi chạy mã này, nextNotifTime sẽ được đặt thành ngày cuối cùng của tháng hiện tại. Hãy ghi nhớ nếu hôm nay là ngày cuối cùng của tháng, hiệu ứng ròng của mã này là đối tượng Lịch không thay đổi.


17

Sau đây sẽ luôn cho kết quả thích hợp:

    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.MONTH, ANY_MONTH);
    cal.set(Calendar.YEAR, ANY_YEAR);
    cal.set(Calendar.DAY_OF_MONTH, 1);// This is necessary to get proper results
    cal.set(Calendar.DATE, cal.getActualMaximum(Calendar.DATE));
    cal.getTime();

Tại sao nó cần thiết? Bạn có thể cho tôi biết :)
Frank Fang

1
Đúng, chỉ có các bài kiểm tra thất bại vì lý do chính xác ở trên. Vấn đề là trừ khi DAY_OF_MONTH được đặt, nó sẽ mặc định là hiện tại.
Pearcy 30/03/2015

7

Sử dụng java.timethư viện mới nhất ở đây là giải pháp tốt nhất:

LocalDate date = LocalDate.now();
LocalDate endOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());

Ngoài ra, bạn có thể làm:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());


2

Nhìn vào getActualMaximum(int field)phương thức của đối tượng Lịch.

Nếu bạn đặt đối tượng Lịch của mình vào tháng mà bạn đang tìm kiếm ngày cuối cùng, thì getActualMaximum(Calendar.DAY_OF_MONTH)sẽ cung cấp cho bạn ngày cuối cùng.


2
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Date date = sdf.parse("11/02/2016");

        Calendar calendar = Calendar.getInstance();  
        calendar.setTime(date);  

        System.out.println("First Day Of Month : " + calendar.getActualMinimum(Calendar.DAY_OF_MONTH));  
        System.out.println("Last Day of Month  : " + calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 

1

Triển khai mở rộng ngày của Kotlin bằng cách sử dụng java.util.Calendar

fun Date.toEndOfMonth(): Date {
    return Calendar.getInstance().apply {
        time = this@toEndOfMonth
    }.toEndOfMonth().time
}

fun Calendar.toEndOfMonth(): Calendar {
    set(Calendar.DAY_OF_MONTH, getActualMaximum(Calendar.DAY_OF_MONTH))
    return this
}

Bạn có thể gọi toEndOfMonthhàm trên mỗi đối tượng Date nhưDate().toEndOfMonth()


4
Các lớp khủng khiếp này đã được thay thế từ nhiều năm trước bởi các lớp java.time hiện đại với việc áp dụng JSR 310. Đề xuất các lớp kế thừa này vào năm 2019 là lời khuyên tồi.
Basil Bourque

Đó là một lời khuyên không tồi. Java.time hiện đại chỉ có sẵn cho Android cho API 26+. Chúng tôi vẫn phụ thuộc vào java.util. * Khi hỗ trợ (không phải vậy) các thiết bị cũ.
Rafael Chagas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.