I am trying to calculate the difference between two LocalDateTime
.
The output needs to be of the format y years m months d days h hours m minutes s seconds
. Here is what I have written:
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.ZoneId;
public class Main {
static final int MINUTES_PER_HOUR = 60;
static final int SECONDS_PER_MINUTE = 60;
static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
public static void main(String[] args) {
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 9, 19, 46, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Period period = getPeriod(fromDateTime, toDateTime);
long time[] = getTime(fromDateTime, toDateTime);
System.out.println(period.getYears() + " years " +
period.getMonths() + " months " +
period.getDays() + " days " +
time[0] + " hours " +
time[1] + " minutes " +
time[2] + " seconds.");
}
private static Period getPeriod(LocalDateTime dob, LocalDateTime now) {
return Period.between(dob.toLocalDate(), now.toLocalDate());
}
private static long[] getTime(LocalDateTime dob, LocalDateTime now) {
LocalDateTime today = LocalDateTime.of(now.getYear(),
now.getMonthValue(), now.getDayOfMonth(), dob.getHour(), dob.getMinute(), dob.getSecond());
Duration duration = Duration.between(today, now);
long seconds = duration.getSeconds();
long hours = seconds / SECONDS_PER_HOUR;
long minutes = ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE);
long secs = (seconds % SECONDS_PER_MINUTE);
return new long[]{hours, minutes, secs};
}
}
The output that I am getting is 29 years 8 months 24 days 12 hours 0 minutes 50 seconds
. I have checked my result from this website (with values 12/16/1984 07:45:55
and 09/09/2014 19:46:45
). The following screenshot shows the output:
I am pretty sure that the fields after the month value is coming wrong from my code. Any suggestion would be very helpful.
Update
I have tested my result from another website and the result I got is different. Here it is: Calculate duration between two dates (result: 29 years, 8 months, 24 days, 12 hours, 0 minutes and 50 seconds).
Update
Since I got two different results from two different sites, I am wondering if the algorithm of my calculation is legitimate or not. If I use following two LocalDateTime
objects:
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
Then the output is coming: 29 years 8 months 25 days -1 hours -5 minutes -10 seconds.
From this link it should be 29 years 8 months 24 days 22 hours, 54 minutes and 50 seconds
. So the algorithm needs to handle the negative numbers too.
Note the question is not about which site gave me what result, I need to know the right algorithm and need to have right results.
And the version of @Thomas in Groovy with takes the desired units in a list instead of hardcoding the values. This implementation (which can easily ported to Java - I made the function declaration explicit) makes Thomas approach more reuseable.
At the time of this writing,the code above returns
47 Years, 8 Months, 9 Days, 22 Hours, 52 Minutes, 7 Seconds, 140 Millis
. And, for @Gennady Kolomoets input, the code returns23 Hours
.When you provide a list of units it must be sorted by size of the units (biggest first):
I found the best way to do this is with ChronoUnit.
Additional documentation is here: https://docs.oracle.com/javase/tutorial/datetime/iso/period.html
It should be simpler!
Unfortunately there doesn't seem to be a period class that spans time as well, so you might have to do the calculations on your own.
Forunately the date and time classes have a lot of utility methods that simplify that to some degree. Here's a way to calculate the difference although not necessarily the fastest:
The basic idea is this: create a temporary start date and get the full years to the end. Then adjust that date by the number of years so that the start date is less then a year from the end. Repeat that for each time unit in descending order.
Finally a disclaimer: I didn't take different timezones into account (both dates should be in the same timezone) and I also didn't test/check how daylight saving time or other changes in a calendar (like the timezone changes in Samoa) affect this calculation. So use with care.
Here a single example using Duration and TimeUnit to get 'hh:mm:ss' format.
There is some problem for Tapas Bose code and Thomas code. If time differenсe is negative, array gets the negative values. For example if
it returns 0 years 0 months 1 days -1 hours 0 minutes 0 seconds.
I think the right output is: 0 years 0 months 0 days 23 hours 0 minutes 0 seconds.
I propose to separate the LocalDateTime instances on LocalDate and LocalTime instances. After that we can obtain the Java 8 Period and Duration instances. The Duration instance is separated on the number of days and throughout-the-day time value (< 24h) with subsequent correction of the period value. When the second LocalTime value is before the firstLocalTime value, it is necessary to reduce the period for one day.
Here's my way to calculate the LocalDateTime difference:
The above method can be used to calculate the difference of any local date and time values, for example:
It is convenient to write a unit test for the above method (both of them are PeriodDuration class members). Here's the code:
}
All tests are successful whether or not the value of the first LocalDateTime is before and for any LocalTime values.