Given 2 dates, how can I calculate the difference between them in Year Month Day, Hour Minute Second format, as per ISO 8601 Durations?
I've only found Java libraries that can give the difference in days or smaller.
Given that months and years have irregular numbers of days, I'm not sure how to figure out the difference in months and years.
Even Duration.between is close but it gives the result in hours minutes seconds:
ZonedDateTime event1 = ZonedDateTime.of(2022, 2, 2, 2, 2, 2, 0, ZoneId.of("UTC-7"));
ZonedDateTime event2 = ZonedDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC-7"));
//ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC-7"));
Duration duration = Duration.between(event1, event2);
Log.d("Duration ISO-8601: ", duration.toString());
Output: PT25533H57M58S
which is 25533 hours, 57 minutes, 58 seconds
I'd like to see something like:
__ years, __ months, __ days, 9 hours, 57 minutes, 58 seconds
CodePudding user response:
I believe I have solved it:
ZonedDateTime event1 = ZonedDateTime.of(2022, 2, 2, 2, 2, 2, 0, ZoneId.of("UTC-7"));
ZonedDateTime event2 = ZonedDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC-7"));
Duration duration = Duration.between(event1, event2);
Period period = Period.between(event1.toLocalDate(), event2.toLocalDate());
Log.d("Duration ISO-8601: ", period.toString() duration.toString());
This prints:
P2Y10M30DPT25533H57M58S
Which is 2 years, 10 months, 30 days, 25533 hours, 57 minutes, 58 seconds.
When extracting the individual values (which is what I need), using modulus fixes the problem with hours:
String.valueOf(duration.toHours() % 24)
And if there's any problem with minutes and seconds, % 60 will fix it.
CodePudding user response:
You can create a custom class that will maintain Period
and Duration
.
class DateTimeSlot {
private Period period;
private Duration duration;
private DateTimeSlot(Period period, Duration duration) {
this.period = period;
this.duration = duration;
}
public static DateTimeSlot of(LocalDateTime from, LocalDateTime to) {
if (from.isAfter(to) || from.equals(to)) {
throw new IllegalArgumentException();
}
Duration duration;
Period period;
if (from.toLocalTime().isBefore(to.toLocalTime())) {
duration = Duration.between(from.toLocalTime(), to.toLocalTime());
period = Period.between(from.toLocalDate(), to.toLocalDate());
} else {
duration = Duration.between(to.withHour(from.getHour())
.withMinute(from.getMinute())
.minusDays(1), to);
period = Period.between(from.toLocalDate(), to.toLocalDate());
}
return new DateTimeSlot(period, duration);
}
@Override
public String toString() {
return "DateTimeSlot{" period duration
'}';
}
}
The toString()
implementation above is very primitive, its purpose only to demonstrate the idea.
main()
- demo
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2022, 5, 20, 18, 0);
LocalDateTime withTimeBefore = LocalDateTime.of(2020, 12, 31, 15,9);
LocalDateTime withTimeAfter = LocalDateTime.of(2020, 12, 31, 22,50);
DateTimeSlot slot1 = DateTimeSlot.of(withTimeBefore, now);
DateTimeSlot slot2 = DateTimeSlot.of(withTimeAfter, now);
System.out.println(slot1);
System.out.println(slot2);
}
Output
DateTimeSlot{P1Y4M20DPT2H51M}
DateTimeSlot{P1Y4M20DPT19H10M}