Вопрос-ответ

How do I calculate someone's age in Java?

Как мне вычислить возраст человека в Java?

Я хочу вернуть возраст в годах в виде int в методе Java. Сейчас у меня есть следующее, где getBirthDate() возвращает объект Date (с датой рождения ;-)):

public int getAge() {
long ageInMillis = new Date().getTime() - getBirthDate().getTime();

Date age = new Date(ageInMillis);

return age.getYear();
}

Но поскольку getYear() устарела, мне интересно, есть ли лучший способ сделать это? Я даже не уверен, что это работает правильно, поскольку у меня нет модульных тестов (пока).

Переведено автоматически
Ответ 1

JDK 8 делает это простым и элегантным:

public class AgeCalculator {

public static int calculateAge(LocalDate birthDate, LocalDate currentDate) {
if ((birthDate != null) && (currentDate != null)) {
return Period.between(birthDate, currentDate).getYears();
} else {
return 0;
}
}
}

Тест JUnit для демонстрации его использования:

public class AgeCalculatorTest {

@Test
public void testCalculateAge_Success() {
// setup
LocalDate birthDate = LocalDate.of(1961, 5, 17);
// exercise
int actual = AgeCalculator.calculateAge(birthDate, LocalDate.of(2016, 7, 12));
// assert
Assert.assertEquals(55, actual);
}
}

К настоящему времени все должны использовать JDK 8. У всех более ранних версий закончился срок поддержки.

Ответ 2

Ознакомьтесь с Joda, которая упрощает вычисления даты и времени (Joda также является основой нового стандартного Java date / time API, так что вы скоро освоите API, который станет стандартным).

например

LocalDate birthdate = new LocalDate (1970, 1, 20);
LocalDate now = new LocalDate();
Years age = Years.yearsBetween(birthdate, now);

это настолько просто, насколько вы могли бы пожелать. Материал до Java 8 (как вы определили) несколько неинтуитивен.

РЕДАКТИРОВАТЬ: в Java 8 есть что-то очень похожее, и с этим стоит ознакомиться.

РЕДАКТИРОВАТЬ: Этот ответ предшествует классам даты и времени Java 8 и больше не является текущим.

Ответ 3

Современный ответ и обзор

a) Java-8 (java.time-package)

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

Пожалуйста, обратите внимание, что предложенное и принятое решение 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.Календарь и т.д.

Для сравнения смотрите Другие ответы. Я бы вообще не рекомендовал использовать эти устаревшие классы, потому что результирующий код по-прежнему содержит ошибки в некоторых экзотических случаях и / или слишком сложный, учитывая тот факт, что исходный вопрос звучит так просто. В 2015 году у нас появились действительно лучшие библиотеки.

d) О Date4J:

Предлагаемое решение простое, но иногда дает сбой в случае високосных лет. Простая оценка дня года ненадежна.

e) Моя собственная библиотека Time4J:

Это работает аналогично Java-8-solution. Просто замените 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
Ответ 4
Calendar now = Calendar.getInstance();
Calendar dob = Calendar.getInstance();
dob.setTime(...);
if (dob.after(now)) {
throw new IllegalArgumentException("Can't be born in the future");
}
int year1 = now.get(Calendar.YEAR);
int year2 = dob.get(Calendar.YEAR);
int age = year1 - year2;
int month3 = now.get(Calendar.MONTH);
int month2 = dob.get(Calendar.MONTH);
if (month2 > month3) {
age--;
} else if (month3 == month2) {
int day1 = now.get(Calendar.DAY_OF_MONTH);
int day2 = dob.get(Calendar.DAY_OF_MONTH);
if (day2 > day1) {
age--;
}
}
// age is now correct
java date