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.
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).
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.
There seems to be some confusion on how to calculate the difference between 2 points in time in Java and how to apply the answers to the OP's question.
Since many people seem to be directed here I'll update my answer to provide a more comprehensive view of what others suggested as well - so kudos to them.
Since Java 8 introduced the java.time
API this answer will only deal with this API. If you're using Java 7 or earlier you could use Joda Time to do something similar.
Before we start with the various approaches, let's establish our test data as per the OP's request:
LocalDateTime fromDateTime = LocalDateTime.of(1984, 12, 16, 7, 45, 55);
LocalDateTime toDateTime = LocalDateTime.of(2014, 9, 10, 6, 40, 45);
If you want to get the difference in a single unit, let's say days or seconds you can directly use several options provided by java.time
:
Duration d = Duration.between(fromDateTime, toDateTime);
long days = d.toDays();
long seconds = d.toSeconds();
Notes:
toXxx()
methods won't return fractional units so the example above would return 10859 days instead of about 10859.95 days.
So if you need fractional units you need to calculate yourself, e.g. double days = d.toMillis() / (24 * 60 * 60 * 1000.0);
(or double days = d.toMillis() / (double)Duration.ofDays(1).toMillis();
)long days = ChronoUnit.DAYS.between(fromDateTime, toDateTime);
long seconds = ChronoUnit.SECONDS.between(fromDateTime, toDateTime);
Notes:
Duration.between(...).toDays()
Duration.toXxx()
this doesn't support fractional units so you'd need to calculate yourself.Duration
may be fasterlong days = fromDateTime.until(toDateTime, ChronoUnit.DAYS);
long days = fromDateTime.until(toDateTime, ChronoUnit.SECONDS);
Notes:
ChronoUnit.between()
actually uses this behind the scenes so the same limitations apply. It's more a matter of style and readbility.Temporal
is implemented by several classes, e.g. LocalDateTime
, LocalTime
, ZonedDateTime
etc.It's "semi-manual" because you'll need to write some form of algorithm to get order right (the manual part) but can still use read-to-use calculations like plusXxx()
and until()
(the automatic part).
LocalDateTime tempDateTime = LocalDateTime.from( fromDateTime );
long years = tempDateTime.until( toDateTime, ChronoUnit.YEARS );
tempDateTime = tempDateTime.plusYears( years );
long months = tempDateTime.until( toDateTime, ChronoUnit.MONTHS );
tempDateTime = tempDateTime.plusMonths( months );
long days = tempDateTime.until( toDateTime, ChronoUnit.DAYS );
tempDateTime = tempDateTime.plusDays( days );
long hours = tempDateTime.until( toDateTime, ChronoUnit.HOURS );
tempDateTime = tempDateTime.plusHours( hours );
long minutes = tempDateTime.until( toDateTime, ChronoUnit.MINUTES );
tempDateTime = tempDateTime.plusMinutes( minutes );
long seconds = tempDateTime.until( toDateTime, ChronoUnit.SECONDS );
System.out.println( years + " years " +
months + " months " +
days + " days " +
hours + " hours " +
minutes + " minutes " +
seconds + " seconds.");
//prints: 29 years 8 months 24 days 22 hours 54 minutes 50 seconds.
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.
Notes:
As of Java 9 (which got published 3 years after the OP's question) the Duration
class now has a couple of toXxxPart()
methods so you could do the following:
Duration d = Duration.between(fromDateTime, toDateTime);
long days = d.toDaysPart();
long seconds = d.toSecondsPart();
Notes:
toDaysPart()
but only 50 seconds from toSecondsPart()
so you'd miss 22 hours and 54 minutes in between.
Using Temporal.until()
as in my original answer gives you the ability to express the example duration as "10859 days and 82490 seconds"The basic idea is to get the milliseconds between the 2 dates and then do your calculations. For sake of simplicity I'll use Duration.toMillis()
but there are other options as well which might be faster.
long millis = Duration.between(fromDateTime, toDateTime).toMillis();
long millisPerDay = 24 * 60 * 60 * 1000; //24 hours * 60 minutes * 60 seconds * 1000 millis
long days = millis / millisPerDay; //example yields 10859
long seconds = millis / 1000; //example yields 938300090
Notes: