Современный ответ и обзор
а) Java-8 (пакет 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
Обратите внимание, что выражение LocalDate.now()
неявно связано с часовым поясом системы (который часто упускается из виду пользователями). Для ясности, как правило, лучше использовать перегруженный метод с now(ZoneId.of("Europe/Paris"))
указанием явного часового пояса (здесь, например, «Европа / Париж»). Если запрашивается системный часовой пояс, то я лично пишу, LocalDate.now(ZoneId.systemDefault())
чтобы сделать связь с системным часовым поясом более ясной. Это больше усилий для написания, но облегчает чтение.
б) йода-тайм
Обратите внимание, что предложенное и принятое решение Joda-Time дает другой результат вычисления для дат, показанных выше (редкий случай), а именно:
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
Я считаю это небольшой ошибкой, но команда Joda по-другому смотрит на это странное поведение и не хочет его исправлять (странно, потому что день месяца конечной даты меньше даты начала, поэтому год должен быть одним меньще). Смотрите также этот закрытый вопрос .
в) java.util.Calendar и т. д.
Для сравнения смотрите различные другие ответы. Я бы вообще не рекомендовал использовать эти устаревшие классы, потому что в некоторых экзотических случаях результирующий код все еще подвержен ошибкам и / или слишком сложен, учитывая тот факт, что исходный вопрос звучит так просто. В 2015 году у нас действительно лучшие библиотеки.
г) О Date4J:
Предложенное решение простое, но иногда терпит неудачу в случае високосных лет. Просто оценка дня года не надежна.
д) Моя собственная библиотека Time4J :
Это работает аналогично Java-8-решению. Просто заменить LocalDate
на PlainDate
и ChronoUnit.YEARS
на CalendarUnit.YEARS
. Однако получение «сегодня» требует явной ссылки на часовой пояс.
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