I want to return an age in years as an int in a Java method. What I have now is the following where getBirthDate() returns a Date object (with the birth date ;-)):
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
Note that the expression LocalDate.now()
is implicitly related to the system timezone (which is often overlooked by users). For clarity it is generally better to use the overloaded method now(ZoneId.of("Europe/Paris"))
specifying an explicit timezone (here "Europe/Paris" as example). If the system timezone is requested then my personal preference is to write LocalDate.now(ZoneId.systemDefault())
to make the relation to the system timezone clearer. This is more writing effort but makes reading easier.
b) Joda-Time
Please note that the proposed and accepted Joda-Time-solution yields a different computation result for the dates shown above (a rare case), namely:
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
I consider this as a small bug but the Joda-team has a different view on this weird behaviour and does not want to fix it (weird because the day-of-month of end date is smaller than of start date so the year should be one less). See also this closed issue.
c) java.util.Calendar etc.
For comparison see the various other answers. I would not recommend using these outdated classes at all because the resulting code is still errorprone in some exotic cases and/or way too complex considering the fact that the original question sounds so simple. In year 2015 we have really better libraries.
d) About Date4J:
The proposed solution is simple but will sometimes fail in case of leap years. Just evaluating the day of year is not reliable.
e) My own library Time4J:
This works similar to Java-8-solution. Just replace LocalDate
by PlainDate
and ChronoUnit.YEARS
by CalendarUnit.YEARS
. However, getting "today" requires an explicit timezone reference.
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