Search code examples
javadatejava-7datediff

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


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?


Solution

  • 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