Элегантный, , казалось бы, правильный , вариант решения Ярона Ронена, основанный на разнице во времени.
Я включаю модульный тест, чтобы доказать, когда и почему он не правильный . Это невозможно из-за (возможно) разного количества високосных дней (и секунд) при любой разнице во времени. Расхождение должно составлять максимум + -1 день (и одна секунда) для этого алгоритма, см. Test2 (), тогда как решение Ярона Ронена, основанное на полностью постоянном предположении timeDiff / MILLI_SECONDS_YEAR
, может отличаться на 10 дней для 40-летнего, тем не менее, этот вариант неверно тоже.
Это сложно, потому что этот улучшенный вариант, использующий формулу diffAsCalendar.get(Calendar.YEAR) - 1970
, большую часть времени возвращает правильные результаты, поскольку число високосных лет в среднем одинаково между двумя датами.
/**
* Compute person's age based on timestamp difference between birth date and given date
* and prove it is INCORRECT approach.
*/
public class AgeUsingTimestamps {
public int getAge(Date today, Date dateOfBirth) {
long diffAsLong = today.getTime() - dateOfBirth.getTime();
Calendar diffAsCalendar = Calendar.getInstance();
diffAsCalendar.setTimeInMillis(diffAsLong);
return diffAsCalendar.get(Calendar.YEAR) - 1970; // base time where timestamp=0, precisely 1/1/1970 00:00:00
}
final static DateFormat df = new SimpleDateFormat("dd.MM.yyy HH:mm:ss");
@Test
public void test1() throws Exception {
Date dateOfBirth = df.parse("10.1.2000 00:00:00");
assertEquals(87, getAge(df.parse("08.1.2088 23:59:59"), dateOfBirth));
assertEquals(87, getAge(df.parse("09.1.2088 23:59:59"), dateOfBirth));
assertEquals(88, getAge(df.parse("10.1.2088 00:00:01"), dateOfBirth));
}
@Test
public void test2() throws Exception {
// between 2000 and 2021 was 6 leap days
// but between 1970 (base time) and 1991 there was only 5 leap days
// therefore age is switched one day earlier
// See http://www.onlineconversion.com/leapyear.htm
Date dateOfBirth = df.parse("10.1.2000 00:00:00");
assertEquals(20, getAge(df.parse("08.1.2021 23:59:59"), dateOfBirth));
assertEquals(20, getAge(df.parse("09.1.2021 23:59:59"), dateOfBirth)); // ERROR! returns incorrect age=21 here
assertEquals(21, getAge(df.parse("10.1.2021 00:00:01"), dateOfBirth));
}
}