Why does the difference between 30 March and 1 March 2020 erroneously give 28 days instead of 29?

JavaDateJava 7Datediff

Java Problem Overview


TimeUnit.DAYS.convert(
   Math.abs(
      new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("30-03-2020 00:00:00").getTime() - 
      new SimpleDateFormat("dd-MM-yyyy HH:mm:ss").parse("1-03-2020 00:00:00").getTime()
   ),
   TimeUnit.MILLISECONDS)

The result is 28, while it should be 29.

Could the time zone/location be the problem?

Java Solutions


Solution 1 - Java

The problem is that because of Daylight Saving Time shift (on Sunday, March 8, 2020), there are 28 days and 23 hours between those dates. TimeUnit.DAYS.convert(...) truncates the result to 28 days.

To see the problem (I'm in US Eastern time zone):

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
            fmt.parse("1-03-2020 00:00:00").getTime();

System.out.println(diff);
System.out.println("Days: " + TimeUnit.DAYS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Hours: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS));
System.out.println("Days: " + TimeUnit.HOURS.convert(Math.abs(diff), TimeUnit.MILLISECONDS) / 24.0);

Output

2502000000
Days: 28
Hours: 695
Days: 28.958333333333332

To fix, use a time zone that doesn't have DST, e.g. UTC:

SimpleDateFormat fmt = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
long diff = fmt.parse("30-03-2020 00:00:00").getTime() -
            fmt.parse("1-03-2020 00:00:00").getTime();

Output

2505600000
Days: 29
Hours: 696
Days: 29.0

Solution 2 - Java

The cause of this problem is already mentioned in Andreas's answer.

The question is what exactly you want to count. The fact that you state that the actual difference should be 29 instead of 28, and ask whether "location/zone time could be a problem", reveals what you actually want to count. Apparently, you want to get rid of any timezone difference.

I assume you only want to calculate the days, without time and timezone.

Java 8

Below, in the example of how the number of days between could be calculated correctly, I'm using a class that represents exactly that – a date without time and timezone – LocalDate.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d-MM-yyyy HH:mm:ss");
LocalDate start = LocalDate.parse("1-03-2020 00:00:00", formatter);
LocalDate end = LocalDate.parse("30-03-2020 00:00:00", formatter);

long daysBetween = ChronoUnit.DAYS.between(start, end);

Note that ChronoUnit, DateTimeFormatter and LocalDate require at least Java 8, which is not available to you, according to the [tag:java-7] tag. However, it perhaps is to future readers.

As mentioned by Ole V.V., there's also the ThreeTen Backport, which backports Java 8 Date and Time API functionality to Java 6 and 7.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJoeView Question on Stackoverflow
Solution 1 - JavaAndreasView Answer on Stackoverflow
Solution 2 - JavaMC EmperorView Answer on Stackoverflow