Berechnung des letzten Tages des Monats

144

Ich habe Probleme mit der Berechnung, wann am nächsten letzten Tag des Monats eine Benachrichtigung gesendet werden soll.

Hier ist mein Code:

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

Dies ist die Linie, die meiner Meinung nach Probleme verursacht:

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

Wie kann ich den Kalender verwenden, um den letzten Tag des nächsten Monats für die Benachrichtigung richtig einzustellen?

OakvilleWork
quelle
1
Stellen Sie den ersten Tag des nächsten Monats ein und rollen Sie dann einen Tag zurück.
Bill
Eine SSCCE würde es einfacher machen, diese Frage zu beantworten. Welches Problem sehen Sie tatsächlich?
DNA

Antworten:

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

Dies gibt das tatsächliche Maximum für den aktuellen Monat zurück. Zum Beispiel ist jetzt Februar des Schaltjahres, also gibt es 29 als zurück int.

AlexR
quelle
danke, ich muss das Maximum für den nächsten Monat bekommen, aber es muss auch noch funktionieren, dass es auch der erste Tag des Monats sein kann, da dieser Teil jetzt funktioniert.
Nochmals
4
Es ist kein Problem, ActualMaximumfür jedes Datum zu bekommen . Rollen Sie die Kalenderinstanz einfach auf das gewünschte Datum, bevor Sie anrufen getActualMaximum. Der erste Termin kann vongetActualMinimum()
AlexR
ok, vielen Dank, Alex. Wenn ich die Instanz auf einen Monat vorab rollen und das getActualMaximum für diesen Monat herausfinden möchte, wie würde ich das tun? Prost
OakvilleWork
Wäre das Alex? nextNotifTime.roll (Calendar.MONTH, true); nextNotifTime.getActualMaximum (Calendar.DAY_OF_MONTH);
OakvilleWork
Außerdem stelle ich danach die Bereitschaftszeit ein. Sollte nextNotification.setReadyDateTime(nextNotifTime.getTime()); ich dies stattdessen nicht tun : nextNotifTime.roll(Calendar.MONTH, true); nextNotifTime.getActualMaximum(Calendar.DAY_OF_MONTH); nextNotifTime.setTime(Calendar.DAY_OF_MONTH); ?
OakvilleWork
61

java.time.temporal.TemporalAdjusters.lastDayOfMonth ()

Mit der java.timein Java 8 integrierten Bibliothek können Sie die TemporalAdjusterSchnittstelle verwenden. In der TemporalAdjustersUtility-Klasse finden wir eine gebrauchsfertige Implementierung : 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

Wenn Sie Zeitinformationen hinzufügen müssen, können Sie alle für LocalDatedie LocalDateTimeKonvertierung verfügbaren wie verwenden

lastDay.atStartOfDay(); //2015-11-30T00:00
Przemek
quelle
Gute Antwort. Aber dieser letzte Teil ist schwach, was auf die Verwendung von hindeutet LocalDateTime. Dieser Klasse fehlt jegliches Konzept der Zeitzone oder des Versatzes von UTC. Es kann also nicht festgestellt werden, wann ein bestimmter Tag an einem bestimmten Ort tatsächlich beginnt. Diese Klasse funktioniert nur für einfache generische 24-Stunden-Tage, nicht für reale Tage. Geben Sie für reale Tage eine Zeitzone an : ZonedDateTime zdt = now.atStartOfDay( ZoneId.of( "Asia/Tokyo" ) ) ;. Einige Tage an einigen Orten können aufgrund von Anomalien wie der Sommerzeit (DST) zu einer anderen Zeit beginnen, z. B. 01:00 Uhr.
Basil Bourque
35

Und um den letzten Tag als Datumsobjekt zu erhalten:

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

Date lastDayOfMonth = cal.getTime();
noch eine andere
quelle
22

Sie können den Kalender auf den ersten des nächsten Monats einstellen und dann einen Tag abziehen.

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

Nach dem Ausführen dieses Codes wird nextNotifTime auf den letzten Tag des aktuellen Monats gesetzt. Wenn heute der letzte Tag des Monats ist, bewirkt dieser Code, dass das Kalenderobjekt unverändert bleibt.

Mike Deck
quelle
17

Folgendes führt immer zu korrekten Ergebnissen:

    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
quelle
Warum ist es notwendig? Könnten Sie mir sagen :)
Frank Fang
1
Ja, gerade hatten Tests aus genau diesem Grund oben fehlgeschlagen. Das Problem ist, dass DAY_OF_MONTH standardmäßig auf aktuell gesetzt wird, sofern es nicht festgelegt ist.
ppearcy
7

Die Verwendung der neuesten java.timeBibliothek ist hier die beste Lösung:

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

Alternativ können Sie Folgendes tun:

LocalDate endOfMonth = date.withDayOfMonth(date.lengthOfMonth());
Satnam
quelle
2

Schaue auf die getActualMaximum(int field) Methode des Kalenderobjekts an.

Wenn Sie Ihr Kalenderobjekt auf den Monat einstellen, für den Sie das letzte Datum suchen getActualMaximum(Calendar.DAY_OF_MONTH), erhalten Sie den letzten Tag.

Bruno
quelle
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
quelle
1

Implementierung der Kotlin-Datumserweiterung mit 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
}

Sie können die toEndOfMonthFunktion für jedes Datumsobjekt wie aufrufenDate().toEndOfMonth()

Gokhan
quelle
4
Diese schrecklichen Klassen wurden vor Jahren durch die modernen Java.time- Klassen mit der Einführung von JSR 310 ersetzt. Es ist ein schlechter Rat, diese Legacy-Klassen im Jahr 2019 vorzuschlagen .
Basil Bourque
Es ist kein schlechter Rat. Die moderne java.time ist für Android nur für API 26+ verfügbar. Wir sind immer noch auf java.util * angewiesen, wenn wir (nicht so) alte Geräte unterstützen.
Rafael Chagas