Nowoczesna odpowiedź i przegląd
a) Java-8 (pakiet java.time)
LocalDate start = LocalDate.of(1996, 2, 29);
LocalDate end = LocalDate.of(2014, 2, 28); // use for age-calculation: LocalDate.now()
long years = ChronoUnit.YEARS.between(start, end);
System.out.println(years); // 17
Zwróć uwagę, że wyrażenie LocalDate.now()
jest niejawnie powiązane ze strefą czasową systemu (która jest często pomijana przez użytkowników). Dla jasności ogólnie lepiej jest użyć przeciążonej metody, now(ZoneId.of("Europe/Paris"))
podając wyraźną strefę czasową (tutaj jako przykład „Europa / Paryż”). Jeśli żądana jest strefa czasowa systemu, to ja wolę pisaćLocalDate.now(ZoneId.systemDefault())
aby powiązanie ze strefą czasową systemu było jaśniejsze. To wymaga większego wysiłku przy pisaniu, ale ułatwia czytanie.
b) Czas Joda
Należy pamiętać, że zaproponowane i zaakceptowane rozwiązanie Joda-Time daje inny wynik obliczeń dla dat pokazanych powyżej (rzadki przypadek), a mianowicie:
LocalDate birthdate = new LocalDate(1996, 2, 29);
LocalDate now = new LocalDate(2014, 2, 28); // test, in real world without args
Years age = Years.yearsBetween(birthdate, now);
System.out.println(age.getYears()); // 18
Uważam to za mały błąd, ale zespół Jody ma inny pogląd na to dziwne zachowanie i nie chce go naprawiać (dziwne, ponieważ data zakończenia miesiąca jest mniejsza niż data rozpoczęcia, więc rok powinien być jeden mniej). Zobacz także to zamknięte wydanie .
c) java.util.Calendar itp.
Dla porównania zobacz różne inne odpowiedzi. W ogóle nie polecałbym używania tych przestarzałych klas, ponieważ wynikowy kod jest nadal podatny na błędy w niektórych egzotycznych przypadkach i / lub zbyt skomplikowany, biorąc pod uwagę fakt, że pierwotne pytanie brzmi tak prosto. W 2015 roku mamy naprawdę lepsze biblioteki.
d) o Date4J:
Proponowane rozwiązanie jest proste, ale czasami zawiedzie w przypadku lat przestępnych. Samo oszacowanie dnia roku nie jest wiarygodne.
e) Moja własna biblioteka Time4J :
Działa to podobnie do rozwiązania Java-8. Po prostu wymień LocalDate
na PlainDate
i ChronoUnit.YEARS
do CalendarUnit.YEARS
. Jednak uzyskanie informacji „dzisiaj” wymaga wyraźnego odniesienia do strefy czasowej.
PlainDate start = PlainDate.of(1996, 2, 29);
PlainDate end = PlainDate.of(2014, 2, 28);
// use for age-calculation (today):
// => end = SystemClock.inZonalView(EUROPE.PARIS).today();
// or in system timezone: end = SystemClock.inLocalView().today();
long years = CalendarUnit.YEARS.between(start, end);
System.out.println(years); // 17