Современный ответ и обзор
а) 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 имеет другой взгляд на это странное поведение и не хочет его исправлять (странно, потому что день месяца конечной даты меньше даты начала, поэтому год должен быть одним меньще). См. Также эту закрытую проблему.
c) 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
person
Meno Hochschild
schedule
02.01.2015