So implementieren Sie die Datumsberechnung in Java

Es gibt viele Fallstricke, von denen Menschen abhängig werden, wenn sie die Implementierung der Datumsberechnung in Java nicht kennen, und es gibt Probleme, also lassen Sie uns sie lösen. Angenommen, Sie möchten das Datum des letzten Tages des nächsten Monats abrufen.

Für Java 8

Es ist besser, die Standard-API, die Datums- und Uhrzeit-API zu verwenden.

LocalDate nextMonth = LocalDate.now().plusMonths(1L);
LocalDate lastDayOfNextMonth = nextMonth.withDayOfMonth(nextMonth.lengthOfMonth());

Wenn Sie dies beispielsweise am 31.08.2016 tun, addiert der Code in der ersten Zeile 1 zum Monat um ".plusMonths (1L)", aber der 31. September existiert nicht, sodass er zuletzt im September gültig ist. Es wird auf den Tag 9/30 angepasst. (In der zweiten Zeile wird auch der letzte Tag des 30. September festgelegt, und lastDayOfNextMonth ist der 30. September 2016) cf.) https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html#plusMonths-long-

Für Java 7 oder niedriger

Die Standard-API kann mit java.util.Calendar implementiert werden.

Calendar calendar = new GregorianCalendar();
calendar.add(Calendar.MONTH, 1);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
Date lastDayOfNextMonth = calendar.getTime();

Jetzt können Sie das Datum des letzten Tages des nächsten Monats abrufen. Wenn Sie dies beispielsweise am 31.08.2016 tun, wird das Hinzufügen von 1 zum 31.09.2016 auf den 30.09. Angepasst. Dies ist der letzte gültige Tag im September, da es sich um ein nicht vorhandenes Datum handelt. Bisher scheint sich die Benutzerfreundlichkeit nicht so stark von der Datums- und Uhrzeit-API zu unterscheiden, aber vergleichen wir die Erklärung im API-Dokument. (Fügen Sie Zeilenumbrüche hinzu, um die Anzeige zu erleichtern.)

Gibt eine Kopie dieses LocalDate plus der angegebenen Anzahl von Monaten zurück.

Diese Methode fügt den angegebenen Betrag in drei Schritten zum Monatsfeld hinzu.

Fügt dem Feld Monat die Anzahl der eingegebenen Monate hinzu Überprüft, ob das resultierende Datum ungültig ist Passen Sie "Monatstag" bei Bedarf auf den letzten gültigen Tag an

Zum Beispiel 2007-03-Wenn Sie den 31. Januar 2007 hinzufügen-04-Es wird ein ungültiges Datum von 31 geben. Anstatt ein ungültiges Ergebnis zurückzugeben 2007, der letzte gültige Tag des Monats-04-30 ist ausgewählt.

Diese Instanz ist unveränderlich und von diesem Methodenaufruf nicht betroffen. ```

Angegeben basierend auf den Regeln des Kalenders(Unterzeichnet)Fügt dem angegebenen Kalenderfeld die Zeit hinzu.

Regel 1 hinzufügen. Der Wert des Feldes nach dem Subtrahieren des Feldwerts im Anruf vor dem Anruf wird zum modularen Überlaufbetrag, der im Feld aufgetreten ist. Ein Überlauf führt dazu, dass der Wert des Felds den Bereich überschreitet, was dazu führt, dass das nächstgrößere Feld inkrementiert oder dekrementiert wird. Tritt auf, wenn der Wert eines Felds so angepasst wird, dass er in diesen Bereich fällt.

Regel 2 hinzufügen. Wenn erwartet wird, dass ein kleines Feld unveränderlich ist, weil sich der minimale oder maximale Wert geändert hat, seit das Feld geändert wurde. Wenn es nicht dem vorherigen Wert entspricht, wird der Wert des Felds so angepasst, dass er dem erwarteten Wert so nahe wie möglich kommt. Kleine Felder Stellt eine kleine Zeiteinheit dar. Stunde ist Tag_OF_Ein Feld kleiner als MONAT. Kleine Felder, von denen nicht erwartet wird, dass sie unveränderlich sind, werden nicht angepasst. Das Kalendersystem bestimmt, welche Felder voraussichtlich unveränderlich sind. ```

Obwohl das Verhalten von LocalDate # plusMonths klar angegeben ist, bin ich mir nicht sicher, was GregorianCalendar # add sagt. .. .. Das Hinzufügen der Regeln 1 und 2 wird ebenfalls am Anfang von http://docs.oracle.com/javase/jp/7/api/java/util/Calendar.html erläutert. Einige Beispiele sind etwas einfacher zu verstehen, aber ich denke, es ist immer noch schwer zu verstehen.

Beispiel:Betrachten Sie zunächst den Gregorianischen Kalender vom 31. August 1999. hinzufügen(Calendar.MONTH, 13)Wenn du anrufst
Der Kalender ist auf den 30. September 2000 eingestellt. Das Hinzufügen von 13 Monaten zum August führt zum September des folgenden Jahres. Fügen Sie also Regel 1 hinzu
Das Feld MONTH ist auf September eingestellt. TAG_OF_MONAT kann nicht am 31. September im Gregorianischen Kalender durchgeführt werden, also durch Hinzufügen von Regel 2
 DAY_OF_MONTH wird auf den nächstmöglichen Wert von 30 eingestellt. Dies ist ein kleines Feld, aber wenn sich der Monat im Gregorianischen Kalender ändert
TAG wie Änderungen geplant sind_OF_WOCHE wird durch Regel 2 nicht angepasst.

Wenn der Monat des nächsten Monats bereits im vorherigen Prozess berechnet wurde und Sie nur den letzten Tag erfassen möchten und Sie versuchen, den nächsten Monat mit der festgelegten Kalendernummer festzulegen, werden Sie möglicherweise von dem unerwarteten Verhalten wie folgt enttäuscht sein.

Calendar calendar = new GregorianCalendar();
calendar.set(Calendar.MONTH,Nächsten Monat);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
Date lastDayOfNextMonth = calendar.getTime();

Der einzige Unterschied zu den oben genannten besteht darin, dass die zweite Zeile anstelle von add gesetzt wird. Wenn Sie dies am 31.07. Ausführen, erhalten Sie das korrekte Ergebnis vom 31.08. Wenn Sie es jedoch am 31.08. Ausführen, erhalten Sie das Ergebnis vom 01.10. Dies liegt daran, dass im Fall von set im Gegensatz zu add ein Übertrag auftritt, wenn das Datum nicht vorhanden ist. Eine andere Sache, die hier zu beachten ist, ist, dass das Ergebnis 10/1 statt 10/31 ist. Wenn es einen Carry gibt, wenn der nächste Monat festgelegt ist, scheint es natürlich, dass es 10/31 sein wird. Um den Wert zum Zeitpunkt der Einstellung im nächsten Monat zu überprüfen, fügen Sie den Code (3. Zeile) hinzu, der den Wert nach dem Festlegen von getTime ausgibt, wie unten gezeigt.

Calendar calendar = new GregorianCalendar();
calendar.set(Calendar.MONTH,Nächsten Monat);
System.out.println(calendar.getTime());
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
Date lastDayOfNextMonth = calendar.getTime();

Das Ergebnis ändert sich zu 31.10. Die Calendar-Klasse enthält intern Felder wie das Datum, und jeder Feldwert wird beim Ausführen der Methode get, der Methode add, der Methode getTime usw. neu berechnet, während die Methode set ein Feld ist. Es wird nicht nur durch Setzen des Werts auf neu berechnet, sondern es wird gemeinsam neu berechnet, wenn get etc. später ausgeführt wird. Mit anderen Worten, zum Zeitpunkt der Einstellung wird dies noch nicht in dem im Kalender festgelegten Datum und der Uhrzeit angezeigt. Wenn getTime in der Mitte des Satzes eingefügt wird, ist das Ergebnis daher unterschiedlich. Ich denke, dies unterscheidet sich von dem Verhalten, das intuitiv erwartet wird. Wenn Sie das Verhalten also nicht gut verstehen, können Sie versehentlich einen Fehler verursachen. Das Verhalten dieser Set-Methode wird auch am Anfang des API-Dokuments http://docs.oracle.com/javase/jp/7/api/java/util/Calendar.html erläutert. (Fügen Sie Zeilenumbrüche hinzu, um die Anzeige zu erleichtern.)

set(f, value)Ändert das Kalenderfeld f in value. Außerdem, um anzuzeigen, dass sich das Kalenderfeld f geändert hat
Interne Mitgliedsvariablen werden gesetzt. Das Kalenderfeld f ändert sich sofort, aber der Kalenderzeitwert(Millisekunde)Ist
get()、getTime()、getTimeInMillis()、add()Oder rollen()Wird erst beim nächsten Anruf neu berechnet.
So setzen()Mehrfaches Aufrufen führt nicht zu unnötigen Berechnungen. einstellen()Wenn Sie das Kalenderfeld mit ändern
Andere Felder können sich je nach Kalenderfeld, Kalenderfeldwert und Kalendersystem ändern.
Darüber hinaus erhalten(f)Gibt nicht immer den eingestellten Wert zurück, indem die set-Methode nach der Neuberechnung des Kalenderfelds aufgerufen wird.
Diese Details werden von der konkreten Kalenderklasse bestimmt.

Beispiel:Betrachten Sie zunächst den Gregorianischen Kalender vom 31. August 1999. einstellen(Calendar.MONTH, Calendar.SEPTEMBER)Wenn du anrufst
Das Datum ist der 31. September 1999. Dies ist eine temporäre interne Darstellung, getTime()Der Aufruf erfolgt am 1. Oktober 1999.
Allerdings getTime()Vor dem Aufruf von set(Calendar.DAY_OF_MONTH, 30)Wenn Sie set anrufen()Weil die Neuberechnung nach sich selbst erfolgt
Das Datum ist auf den 30. September 1999 festgelegt.

Im Fall der Java 8-API für Datum und Uhrzeit

LocalDate nextMonth = LocalDate.now().withMonth(Nächsten Monat);
LocalDate lastDayOfNextMonth = nextMonth.withDayOfMonth(nextMonth.lengthOfMonth());

Selbst wenn der Code, der den nächsten Monat angibt, wie im Fall von add am 31.08. Ausgeführt wird, ist das Ergebnis 9/30. Das API-Dokument https://docs.oracle.com/javase/jp/8/docs/api/java/time/LocalDate.html#withMonth-int- enthält auch die folgende Beschreibung, sodass Sie sicher sein können.

Wenn dieser "Monatstag" für dieses Jahr ungültig ist, wird er auf den letzten gültigen Tag des Monats geändert.

Außerdem plane ich, den September als Fehler festzulegen, den Anfänger machen, was für den Kalender nicht intuitiv ist.

calendar.set(Calendar.MONTH, 9);

Es gibt auch einen Fall, in dem es geschrieben ist. Eigentlich bedeutet dies, dass der Oktober festgelegt wurde. Der Kalendermonat ist 0-11, nicht 1-12. Wenn Sie also den September angeben möchten

calendar.set(Calendar.MONTH, 8);

Muss geschrieben werden. Es ist schwer, intuitiv zu lesen und zu verstehen

calendar.set(Calendar.MONTH, Calendar.SEPTEMBER);

Es ist besser, mit Konstanten wie zu schreiben.

Was soll ich machen?

Wenn Sie das oben beschriebene Verhalten der Calendar-Klasse genau kennen, möchten Sie möglicherweise Calendar verwenden, dies ist jedoch kompliziert. Mit Joda-Time http://www.joda.org/joda-time/, einem festen Bestandteil der Datumsbibliotheken in Java vor Java 7, können Sie wie folgt direkt schreiben.

Date lastDayOfNextMonth = LocalDate.now().plusMonths(1).dayOfMonth().withMaximumValue().toDate();

Um den Monat des nächsten Monats anzugeben, ist dies wie folgt.

Date lastDayOfNextMonth = LocalDate.now().withMonthOfYear(Nächsten Monat).dayOfMonth().withMaximumValue().toDate();

Wenn Sie Joda-Time nicht verwenden und in Zukunft eine Migration auf Java 8 in Betracht ziehen, machen Sie es zu einem Joda-Time-Entwickler und lesen Sie die Spezifikationen der Datums- und Zeit-API (JSR-310). Stephen Colebourne hat ThreeTen-Backport http://www.threeten.org/threetenbp/ als Bibliothek veröffentlicht, die Java8-API-Klassen für Datum und Uhrzeit für Java6 / 7 zurückportiert. Verwenden Sie diese Option. Ich finde es auch gut.

Recommended Posts

So implementieren Sie die Datumsberechnung in Java
So implementieren Sie den Kalman-Filter mit Java
So erzwingen Sie Codierungskonventionen in Java
So erhalten Sie das Datum mit Java
[Java] So implementieren Sie Multithreading
Zusammenfassung der Implementierung von Standardargumenten in Java
Wie man JAVA in 7 Tagen lernt
Wie verwende ich Klassen in Java?
So benennen Sie Variablen in Java
Versuchen Sie, Yuma in Java zu implementieren
So verketten Sie Zeichenfolgen mit Java
So implementieren Sie Suchfunktionen in Rails
Mehrsprachige Unterstützung für Java Verwendung des Gebietsschemas
Versuchen Sie, n-ary Addition in Java zu implementieren
So führen Sie eine Basiskonvertierung in Java durch
[Java] So stellen Sie die Datums- und Uhrzeit auf 00:00:00 ein
So beheben Sie das Systemdatum in JUnit
Einbetten von Janus Graph in Java
So implementieren Sie Ranking-Funktionen in Rails
So implementieren Sie die asynchrone Verarbeitung in Outsystems
So implementieren Sie einen Job, der die Java-API in JobScheduler verwendet
Datumsmanipulation in Java 8
So zeigen Sie eine Webseite in Java an
So erhalten Sie eine Klasse von Element in Java
So verbergen Sie Nullfelder als Antwort in Java
So implementieren Sie eine ähnliche Funktion in Rails
So implementieren Sie optimistisches Sperren in der REST-API
So lösen Sie Ausdrucksprobleme in Java
Wie schreibe ich Java String # getBytes in Kotlin?
So implementieren Sie Paginierung in GraphQL (für Ruby)
[Java] Verwendung der Kalenderklasse und der Datumsklasse
So implementieren Sie UICollectionView mit Code nur in Swift
So erstellen Sie eine Java-Umgebung in nur 3 Sekunden
[Java] So lassen Sie den privaten Konstruktor in Lombok weg
So implementieren Sie die Gastanmeldung in 5 Minuten im Rails-Portfolio
So senken Sie die Java-Version
[Java] Verwendung von Map
So implementieren Sie eine nette Funktion in Ajax mit Rails
So deinstallieren Sie Java 8 (Mac)
Ich habe versucht, die Firebase-Push-Benachrichtigung in Java zu implementieren
Java - So erstellen Sie JTable
Wie kann ich IBM Mainframe-Dateien in Java eingeben / ausgeben?
Verwendung von Java Optional
So minimieren Sie Java-Images
Wie schreibe ich einen Java-Kommentar
Implementierung der zweistufigen Authentifizierung in Java
Verwendung der Java-Klasse
So erstellen Sie einen Daten-URI (base64) in Java
[Java] Verwendung von removeAll ()
[Java] So zeigen Sie Wingdings an
Implementieren Sie die Standardauthentifizierung in Java
Verwendung von Java Map
Implementieren Sie eine Kombination aus Mathematik in Java
So schreiben Sie eine Datumsvergleichssuche in Rails