You can create a custom class that will maintain Period
and Duration
fields (credits to @Ole V.V. since he mentioned it earlier in the comments).
Here is an example of such a class implementation, which exposes a static method between()
, that expects two arguments of type LocalDateTime
.
Methods like getYears()
and getHours()
will delegate the call to Period
and Duration
objects.
class DateTimeSlot {
private Period period;
private Duration duration;
private DateTimeSlot(Period period, Duration duration) {
this.period = period;
this.duration = duration;
}
public int getYears() {
return period.getYears();
}
public int getMonth() {
return period.getMonths();
}
public int getDays() {
return period.getDays();
}
public int getHours() {
return duration.toHoursPart(); // this method can be safely used instead `toHours()` because `between()` implementation guerantees that duration will be less than 24 hours
}
public int getMinutes() {
return duration.toMinutesPart();
}
public int getSeconds() {
return (int) (duration.getSeconds() % 60);
}
public static DateTimeSlot between(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())
.withSecond(from.getSecond())
.minusDays(1), to); // apply shift one day back
period = Period.between(from.toLocalDate()
.plusDays(1), to.toLocalDate()); // apply shift one day forward (to compensate the previous shift)
}
return new DateTimeSlot(period, duration);
}
@Override
public String toString() {
return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",
getYears(), getMonth(), getDays(), getHours(), getMinutes(), getSeconds());
}
}
main()
- demo
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2022, 5, 20, 18, 0, 18);
LocalDateTime withTimeBefore = LocalDateTime.of(2020, 12, 31, 15, 9, 27);
LocalDateTime withTimeAfter = LocalDateTime.of(2020, 12, 31, 22, 50, 48);
DateTimeSlot slot1 = DateTimeSlot.between(withTimeBefore, now);
DateTimeSlot slot2 = DateTimeSlot.between(withTimeAfter, now);
System.out.println(slot1);
System.out.println(slot2);
}
Output
1 years, 4 months, 20 days, 2 hours, 50 minutes, 51 seconds // between 2020-12-31T15:09:27 and 2022-05-20T18:00:18
1 years, 4 months, 19 days, 19 hours, 9 minutes, 30 seconds // between 2020-12-31T22:50:48 and 2022-05-20T18:00:18