2015-10-05 9 views
9

Bei der Berechnung von Jahren zwischen zwei Daten, wobei das zweite Datum aus dem ersten berechnet wird (dies ist ein vereinfachtes Beispiel dessen, woran ich gerade arbeite), scheinen LocalDate und Period ein Jahr zu berechnen etwas anders.Berechnung von Jahren zwischen einem Schaltjahr

Zum Beispiel

LocalDate date = LocalDate.of(1996, 2, 29); 
LocalDate plusYear = date.plusYears(1); 
System.out.println(Period.between(date, plusYear).getYears()); 

während

LocalDate date = LocalDate.of(1996, 3, 29); 
LocalDate plusYear = date.plusYears(1); 
System.out.println(Period.between(date, plusYear).getYears()); 

Trotz ein Jahr erste Period Rückkehr der Jahre als 0, während der zweite Fall kehrt 1 explizit hinzugefügt hat.

Gibt es eine nette Lösung?

+0

Ich glaube, dass Ihr Produktionscode nicht wirklich 1 Jahr hinzufügt und versucht zu zählen, wie viele Jahre es gerade hinzugefügt hat. Was versuchst du eigentlich zu erreichen? Geben Sie uns die tatsächliche Eingabe und erwartete Ausgabe. – dotvav

+3

@dotvav: Das gegebene Beispiel scheint mir ziemlich klar zu sein ... Ich sehe nichts falsch daran. –

+0

Wenn Sie wirklich einen Jahresunterschied statt Null wollen, dann subtrahieren Sie einfach die Jahreszahlen, die keine Monats- oder Tagestage-Teile berücksichtigen. –

Antwort

3

Diese Frage hat eine philosophische Natur und umfasst wenige Probleme wie Zeitmessungen und Datumsformatkonventionen.

LocalDate ist eine Implementierung von ISO 8601 Datum Austauschstandard. Java Doc gibt explizit an, dass diese Klasse keine Zeit darstellt, sondern nur die Standarddatumsnotation bereitstellt.

Die API bietet nur einfache Operationen auf die Notation selbst und alle Berechnungen werden durch Erhöhen der Jahr getan, oder Monat oder Tag von einem bestimmten Zeitpunkt.

Mit anderen Worten, wenn Sie LocalDate.plusYears() aufrufen, fügen Sie konzeptionelle Jahre von 365 Tagen jedes statt der genauen Menge an Zeit innerhalb eines Jahres hinzu.

Dies macht Tag die niedrigste Zeiteinheit, die man zu einem Datum hinzufügen kann, ausgedrückt durch LocalDate.

In menschlichen Verständnis, Datum ist kein Moment in der Zeit, aber es ist eine Zeit.

Es beginnt mit 00h 00m 00s (...) und endet mit 23h 59m 59s (...).

LocalDate vermeidet jedoch Probleme mit der Zeitmessung und Unbestimmtheit der menschlichen Zeiteinheiten (Stunde, Tag, Monat und ein Jahr alle unterschiedlich lang sein kann) und Modelle Datum Notation einfach als Tupel :

(years, months within a year, days within a month)

seit dem Beginn der Ära berechnet. In dieser Interpretation macht es Sinn, dass Tag die kleinste Einheit ist, die das Datum beeinflusst.

Als Beispiel folgende:

LocalDate date = LocalDate.of(1996, 2, 29); 
LocalDate plusSecond = date.plus(1, ChronoUnit.SECONDS); 

kehrt

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Seconds 

..., die zeigt, dass die Verwendung von LocalDate und Hinzufügen der Anzahl von Sekunden, Sie (oder kleinere Einheiten, die Genauigkeit zu fahren) konnte die in Ihrer Frage aufgeführte Einschränkung nicht überwinden.

Mit Blick auf die Implementierung finden Sie, dass LocalDate.plusYears() nach dem Hinzufügen der Jahre, Anrufe resolvePreviousValid(). Dieses Verfahren prüft dann für Schaltjahr und modifiziert das Tag Feld in folgenden Weise:

day = Math.min(day, IsoChronology.INSTANCE.isLeapYear((long)year)?29:28);

Mit anderen Worten: es korrigiert sich um 1 Tag wirksam abgezogen.

könnten Sie Year.length() benutzen, die die Anzahl der Tage für bestimmtes Jahr zurückkehrt und werden für Schaltjahre zurück. So könnten Sie tun:

LocalDate plusYear = date.plus(Year.of(date.getYear()).length(), ChronoUnit.DAYS); 

Sie noch in laufen Merkwürdigkeiten folgende (Aufruf zum Year.length() den Tag zählt der Kürze ersetzt):

LocalDate date = LocalDate.of(1996, 2, 29); 
LocalDate plusYear = date.plus(365, ChronoUnit.DAYS); 
System.out.println(plusYear); 
Period between = Period.between(date, plusYear); 
System.out.println(between.getYears() + "y " + 
        between.getMonths() + "m " + 
        between.getDays() + "d"); 

kehrt

1997-02-28 
0y 11m 30d 

dann

LocalDate date = LocalDate.of(1996, 3, 29); 
LocalDate plusYear = date.plus(365, ChronoUnit.DAYS); 
System.out.println(plusYear); 
Period between = Period.between(date, plusYear); 
System.out.println(between.getYears() + "y " + 
        between.getMonths() + "m " + 
        between.getDays() + "d"); 

kehrt

1997-03-29 
1y 0m 0d 

und schließlich:

LocalDate date = LocalDate.of(1996, 2, 29); 
LocalDate plusYear = date.plus(366, ChronoUnit.DAYS); 
System.out.println(plusYear); 
Period between = Period.between(date, plusYear); 
System.out.println(between.getYears() + "y " + 
        between.getMonths() + "m " + 
        between.getDays() + "d"); 

kehrt:

1997-03-01 
1y 0m 1d 

Bitte beachten Sie, dass das Datum von statt Tage bewegt den Zeitraum von erhöht 11 Monate und 30 Tage bis 1 Jahr und 1 Tag (2 Tage erhöhen!).

Verwandte Themen