I have a formatter as below:
private static PeriodFormatter formatter = new PeriodFormatterBuilder()
.printZeroNever()
.appendYears().appendSuffix(" years ")
.appendMonths().appendSuffix(" months ")
.appendWeeks().appendSuffix(" weeks ")
.appendDays().appendSuffix(" days ")
.appendHours().appendSuffix(" hours ")
.appendMinutes().appendSuffix(" minutes ")
.appendSeconds().appendSuffix(" seconds")
.toFormatter();
and use it as below:
DateTime dt = DateTime.parse("2010-06-30T01:20");
Duration duration = new Duration(dt.toInstant().getMillis(), System.currentTimeMillis());
Period period = duration.toPeriod().normalizedStandard(PeriodType.yearMonthDayTime());
formatter.print(period);
the output is:
2274 days 13 hours 59 minutes 39 seconds
So where is the years?
The underlying problem here is your use of Duration
to start with, IMO. A Duration
is just a number of milliseconds... it's somewhat troublesome to consider the number of years in that, as a year is either 365 or 366 days (and even that depends on the calendar system). That's why the toPeriod
method you're calling explicitly says:
Only precise fields in the period type will be used. Thus, only the hour, minute, second and millisecond fields on the period will be used. The year, month, week and day fields will not be populated.
Then you're calling normalizedStandard(PeriodType)
which includes:
The days field and below will be normalized as necessary, however this will not overflow into the months field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. But a period of 1 month 40 days will remain as 1 month 40 days.
Rather than create the period from a Duration
, create it directly from the DateTime
and "now", e.g.
DateTime dt = DateTime.parse("2010-06-30T01:20");
DateTime now = DateTime.now(); // Ideally use a clock abstraction for testability
Period period = new Period(dt, now, PeriodType.yearMonthDayTime());
See more on this question at Stackoverflow