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

Joe picture Joe · Feb 5, 2020 · Viewed 14.2k times · Source
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?

Answer

Andreas picture Andreas · Feb 5, 2020

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