2015-10-05 16 views
9

Podczas obliczania lat między dwiema datami, gdzie druga data jest obliczana od pierwszej (jest to uproszczony przykład tego, nad czym pracuję), LocalDate i Period wydają się obliczać rok trochę inaczej.Obliczanie lat między rokiem przestępnym

Przykładowo

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

podczas

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

Pomimo wyraźnie dodano roku, pierwszy Period powrotu lata w 0, natomiast drugi przypadek zwraca 1.

Czy jest to porządny sposób?

+0

Wydaje mi się, że Twój kod produkcyjny faktycznie nie dodaje 1 roku i nie liczy się z liczbą dodanych lat. Co tak naprawdę próbujesz osiągnąć? Podaj nam rzeczywiste dane wejściowe i oczekiwane wyniki. – dotvav

+3

@dotvav: Podany przykład wydaje mi się całkiem jasny ... Nie widzę w tym nic złego. –

+0

Jeśli naprawdę chcesz mieć roczną różnicę zamiast zera, po prostu odejmij numery roku nie biorąc pod uwagę miesiąca lub dnia w miesiącu. –

Odpowiedz

3

To pytanie ma charakter filozoficzny i obejmuje kilka problemów, takich jak pomiary czasu i konwencje dotyczące formatu daty.

LocalDate to implementacja standardu wymiany danych . Java Doc stwierdza jednoznacznie, że ta klasa nie reprezentuje czasu, ale zapewnia tylko standardowy zapis daty.

API zapewnia tylko proste operacje na samej notacji i wszystkie obliczenia wykonywane są przez przyrostowe zwiększenie Rok lub Miesiąc lub Dzień na dany dzień.

Innymi słowy, dzwoniąc pod numer LocalDate.plusYears(), dodajesz lata koncepcyjne o długości 365 dni, a nie dokładną ilość czasu w ciągu roku.

To sprawia, że ​​dzień najniższa jednostka czasu, którą można dodać do daty wyrażonej przez LocalDate.

W rozumieniu ludzi, data nie jest momentem czasu, ale jest to okres.

Rozpoczyna się od 00h 00m 00s (...) i kończy się 23h 59m 59s (...).

LocalDate jednak uniknąć problemów z pomiarem czasu i niejasności jednostek czasowych ludzkich (godzinnym, dni, miesięcy, a rok wszystko może mieć różne długości) i modele datę zapisu po prostu jako krotki :

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

obliczany od początku ery.

W tej interpretacji ma sens, że Dzień jest najmniejszą jednostką wpływającą na datę.

Jako przykład następujący:

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

zwrotów

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

... co pokazuje, że przy użyciu LocalDate i dodając liczbę sekund (lub mniejszych jednostek do prowadzenia precyzji), ty nie udało się przezwyciężyć ograniczeń wymienionych w pytaniu.

Patrząc na wdrożenie, po dodaniu lat znajduje się LocalDate.plusYears(), nazywa się resolvePreviousValid(). Metoda ta sprawdza na rok przestępny i modyfikuje pole dzień w następujący sposób:

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

Innymi słowy koryguje ją skutecznie odjęcie 1 dzień.

Można użyć numeru Year.length(), który zwraca liczbę dni dla danego roku i zwróci dla lat przestępnych. Więc można zrobić:

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

Będziesz nadal działać w następujący osobliwości (wezwanie do Year.length() zastąpione liczbą dziennie dla zwięzłość):

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"); 

zwrotów

1997-02-28 
0y 11m 30d 

następnie

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"); 

powraca

1997-03-29 
1y 0m 0d 

i wreszcie:

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"); 

Powroty:

1997-03-01 
1y 0m 1d 

Należy pamiętać, że przesunięcie terminu przez zamiast dni wzrosła okres od 11 miesięcy i 30 dni do 1 rok i 1 dzień (wzrost o 2 dni!).

Powiązane problemy