Risposta moderna e panoramica
a) Java-8 (pacchetto 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
Si noti che l'espressione LocalDate.now()
è implicitamente correlata al fuso orario del sistema (che viene spesso trascurato dagli utenti). Per chiarezza è generalmente meglio usare il metodo sovraccarico now(ZoneId.of("Europe/Paris"))
specificando un fuso orario esplicito (qui "Europa / Parigi" come esempio). Se viene richiesto il fuso orario del sistema, la mia preferenza personale è quella di scrivere LocalDate.now(ZoneId.systemDefault())
per rendere più chiara la relazione con il fuso orario del sistema. Questo è più sforzo di scrittura ma rende più facile la lettura.
b) Joda-Time
Si noti che la soluzione Joda-Time proposta e accettata produce un risultato di calcolo diverso per le date indicate sopra (un caso raro), vale a dire:
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
Lo considero un piccolo bug ma il team di Joda ha una visione diversa di questo strano comportamento e non vuole risolverlo (strano perché il giorno del mese della data di fine è più piccolo della data di inizio, quindi l'anno dovrebbe essere uno in meno). Vedi anche questo numero chiuso .
c) java.util.Calendario ecc.
Per un confronto vedi le altre risposte. Non consiglierei affatto di usare queste classi obsolete perché il codice risultante è ancora soggetto a errori in alcuni casi esotici e / o in modo troppo complesso considerando il fatto che la domanda originale sembra così semplice. Nel 2015 abbiamo biblioteche davvero migliori.
d) Informazioni su Date4J:
La soluzione proposta è semplice ma a volte fallirà in caso di anni bisestili. La valutazione del giorno dell'anno non è affidabile.
e) La mia libreria Time4J :
Funziona in modo simile alla soluzione Java-8. Basta sostituire LocalDate
entro PlainDate
e ChronoUnit.YEARS
per CalendarUnit.YEARS
. Tuttavia, ottenere "oggi" richiede un riferimento di fuso orario esplicito.
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