最新の回答と概要
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())
、システムのタイムゾーンとの関係をより明確にするために書くことです。これはより多くの書き込み作業ですが、読みやすくなります。
b)ジョーダタイム
提案され承認されたJoda-Time-solutionは、上記の日付(まれなケース)に対して異なる計算結果を生成することに注意してください。
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チームはこの奇妙な動作について別の見方をしており、修正したくありません(奇妙なことに、終了日は開始日よりも短いため、年は1つ少ない)。この終了した問題も参照してください。
c)java.util.Calendarなど
比較のために、他のさまざまな回答を参照してください。元の質問が非常に単純に聞こえるという事実を考慮すると、結果として得られるコードは一部のエキゾチックなケースでエラーが発生しやすく、複雑すぎるため、これらの古いクラスを使用することはお勧めしません。2015年には、本当に良い図書館ができました。
d)Date4Jについて:
提案された解決策は単純ですが、うるう年の場合には失敗することがあります。年の日を評価するだけでは信頼できません。
e)私自身のライブラリ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