perhitungan hari terakhir bulan

144

Saya mengalami masalah dengan perhitungan kapan Hari Terakhir Bulan berikutnya untuk pemberitahuan yang dijadwalkan akan dikirim.

Ini kode saya:

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

Inilah garis yang menyebabkan masalah yang saya yakini:

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

Bagaimana saya bisa menggunakan Kalender untuk mengatur hari terakhir bulan berikutnya untuk notifikasi?

OakvilleWork
sumber
1
Atur ke hari pertama bulan berikutnya dan kemudian mundur satu hari.
Tagihan
Sebuah SSCCE akan membuat lebih mudah untuk menjawab pertanyaan ini. Masalah apa yang sebenarnya Anda lihat?
DNA

Jawaban:

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

Ini mengembalikan maksimum aktual untuk bulan ini. Misalnya sekarang Februari tahun kabisat, jadi mengembalikan 29 sebagai int.

AlexR
sumber
terima kasih, saya perlu mendapatkan maks untuk bulan berikutnya, tetapi masih harus bekerja bahwa itu bisa menjadi hari pertama bulan itu juga, karena bagian itu berfungsi sekarang. terima kasih sekali lagi atas waktu dan usaha Anda
OakvilleWork
4
Bukan masalah untuk mendapatkan ActualMaximumsetiap kencan. Cukup putar instance kalender ke tanggal yang diperlukan sebelum menelepon getActualMaximum. Tanggal pertama dapat diperoleh dengangetActualMinimum()
AlexR
ok terima kasih banyak Alex, jadi jika saya ingin memutar contoh untuk satu bulan ke depan dan mencari tahu getActualMaximum untuk bulan itu bagaimana saya melakukannya ?? Cheers
OakvilleWork
apakah ini Alex? nextNotifTime.roll (Calendar.MONTH, true); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork
juga saya mengatur siap tanggal waktu setelah ini: nextNotification.setReadyDateTime(nextNotifTime.getTime()); karena itu harus saya tidak melakukan ini sebagai gantinya: nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork
61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Menggunakan java.timeperpustakaan yang dibangun ke Java 8, Anda dapat menggunakan TemporalAdjusterantarmuka. Kami menemukan sebuah implementasi siap untuk digunakan dalam TemporalAdjusterskelas utilitas: 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

Jika Anda perlu menambahkan informasi waktu, Anda dapat menggunakan yang tersedia LocalDateuntuk LocalDateTimekonversi seperti

lastDay.atStartOfDay(); //2015-11-30T00:00
Przemek
sumber
Jawaban yang bagus. Tetapi bagian terakhir itu lemah, menyarankan penggunaan LocalDateTime. Kelas itu tidak memiliki konsep zona waktu atau offset-dari-UTC. Jadi itu tidak dapat menentukan kapan hari tertentu di tempat tertentu benar-benar dimulai. Kelas itu hanya berfungsi untuk 24 jam sehari, bukan hari biasa. Untuk hari nyata, menentukan zona waktu: ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Beberapa hari di beberapa tempat dapat dimulai pada waktu yang berbeda, seperti 01:00, karena anomali seperti Daylight Saving Time (DST).
Basil Bourque
35

Dan untuk mendapatkan hari terakhir sebagai objek Date:

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

Date lastDayOfMonth = cal.getTime();
yetAnSESE
sumber
22

Anda dapat mengatur kalender menjadi yang pertama bulan berikutnya dan kemudian kurangi satu hari.

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

Setelah menjalankan kode ini nextNotifTime akan ditetapkan ke hari terakhir bulan ini. Ingatlah bahwa jika hari ini adalah hari terakhir dalam bulan, efek bersih dari kode ini adalah bahwa objek Kalender tetap tidak berubah.

Mike Deck
sumber
17

Berikut ini akan selalu memberikan hasil yang tepat:

    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();
Safvan Kothawala
sumber
Kenapa itu perlu? Bisakah Anda ceritakan :)
Frank Fang
1
Yap, baru saja tes gagal karena alasan tepat di atas. Masalahnya adalah bahwa kecuali DAY_OF_MONTH diatur, default akan menjadi saat ini.
ppearcy
7

Menggunakan java.timeperpustakaan terbaru di sini adalah solusi terbaik:

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

Atau, Anda dapat melakukan:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
satnam
sumber
2

Lihatlah getActualMaximum(int field) metode objek Kalender.

Jika Anda menetapkan objek Kalender Anda berada di bulan yang Anda cari tanggal terakhir, maka getActualMaximum(Calendar.DAY_OF_MONTH)akan memberi Anda hari terakhir.

Bruno
sumber
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)); 
Kishore Kumar
sumber
1

Penggunaan ekstensi tanggal Kotlin menggunakan 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
}

Anda dapat memanggil toEndOfMonthfungsi pada setiap objek Date likeDate().toEndOfMonth()

gokhan
sumber
4
Kelas-kelas yang mengerikan ini digantikan tahun yang lalu oleh kelas java.time modern dengan adopsi JSR 310. Menyarankan kelas-kelas warisan ini pada tahun 2019 adalah saran yang buruk.
Basil Bourque
Itu bukan saran yang buruk. Java.time modern hanya tersedia untuk Android untuk API 26+. Kami masih bergantung pada java.util. * Ketika mendukung (tidak demikian) perangkat lama.
Rafael Chagas