Paul Hill, August 2004

On and off for many years, I have seen people post to comp.lang.java.programmer
questions about calculating differences between two dates. Many people think
that calculating the difference in days is a simple exercise. They even post
code that they believe demonstrates the trivial solution. The problem is that
the obvious solution -- subtracting the millisecond timestamps of two moments
and
dividing
by the
number of milliseconds per day, contains a bug. **The bug in this trivial
calculation is that in many areas of the world where there is daylight
savings time,
one day is 23 hours long and another is 25 hours long_{1}. **This
bug is not a limitation of either java.util.Date or java.util.Calendar,
but is
a characteristic of the definition of the calendar day in many locations, thus
it is common to any day calculation involving millisecond values.

There are two concepts we can use to define the difference in days between
two date time stamps, both are very useful in certain situations. The first
idea I call **delta
calendar days**. It assumes
any time today subtracted from any time tomorrow
results in a 1 day difference, thus 0 = today, 1 = tomorrow, 2 = the day after
tomorrow, -1 = yesterday, -2 = the day before yesterday. The other idea I shall
call **delta day periods**. It assumes that the difference
between some time today and the same clock time tomorrow is exactly 1 day.
If the difference
between the times
is
greater
than
the period of a day,
the value is larger. These differences are shown in Table 1

**Table 1: **Two different day difference definitions

Datetime 1 |
Datetime 2 |
Delta Calendar Days |
DeltaDay Periods |
---|---|---|---|

2004-01-0 1 8:00 |
2004-01-02 09:00 |
1 | 1 day 1 hour |

2004-01-0 1 8:00 |
2004-01-03 11:00 |
2 | 2 days 3 hours |

2004-01-0 1 8:00 |
2004-01-04 13:00 |
3 | 3 days 5 hours |

2004-01-0 1 8:00 |
2003-12-31 09:00 |
-1 | 0 days 23 hours |

2004-01-0 1 8:00 |
2003-12-30 11:00 |
-2 | 1 day 21 hours |

2004-01-0 1 8:00 |
2003-12-29 13:00 |
-3 | 2 days 19 hours |

The first approximation for delta day periods -- the calculation which is "trivial and obvious" to many -- would seem to be

java.util.Date lateDate, earlyDate;

deltaDays = ( lastDate.getTime() - earlyDate.getTime() )/ MILLSECS_PER_DAY;

But this is **not** correct. If we choose the dates in the spring
around the "spring forward" date and the date in the autumn of the "fall
back" date
we can see the problem.

**Table 2: **Day differences
compared to 24 hour periods, including at the DLS change dates.

Datetime 1 |
Datetime 2 |
Delta Calendar Days |
DeltaDay Periods |
Delta24-hour Periods |
---|---|---|---|---|

2004-04-01 T 06:00:00.0 PST | 2004-04-02 T 06:00:00.0 PST |
1 | 1 | 1 |

2004-04-01 T 06:00:00.0 PST | 2004-04-03 T 06:00:00.0 PST |
2 | 2 | 2 |

2004-04-01 T 06:00:00.0 PST |
2004-04-04 T 06:00:00.0 PDT |
3 | 3 | 2 |

2004-10-31 T 00:00:01.0 PDT |
2004-10-31 T 23:59:59.0 PST |
0 | 0 | 1 |

The last two dates in the above chart calculate through the daylight savings change date in the North American "Pacific" timezone which includes Vancouver CA; Seattle, San Francisco and Los Angeles USA.

Using 24-hour periods is an inappropriate solution because:

Listing 1 is **FAQCalendar** which
subclasses java.util.Gregoriancalendar and
provides methods to calculate:

diffDayPeriods( Calendar), get24HourPeriods(Calendar).

The diffDayPeriods calculation includes using the timezone offset for the current time and hence the correct DLS offset in the difference calculation. The key statements are:

```
long endL = end.getTimeInMillis() + end.getTimeZone().getOffset(
end.getTimeInMillis() );
```

long startL = this.getTimeInMillis() + this.getTimeZone().getOffset( this.getTimeInMillis() );

return (endL - startL) / MILLISECS_PER_DAY;

The method get24HourPeriods(Calendar) has been marked as deprecated.

Listing 2 is **DeltaDays** which is a Junit Test which will test all the methods
discussed above to calculate a difference in days.

I would not recommend using the "trivial and obvious" method when calculating the number of days between datetime values because of the problems with daylight savings. The correct calculation depends on your needs, but may include knowing the correct DLS offset for the times in the calculation. Luckily, this timezone and DLS offset value can be obtained from within a java.util.Calendar.

Further general information about bad date calculations can be found at
**The Best of Dates, The Worst Of Dates**, see particularly section 8.4 Length Of Day Bugs. The current article corrects the common error "advancing to the next Civil Day by adding 24*60*60 (86,400) seconds to the current time"** _{2}** and avoids "Using your own logic to manipulate a time rather than calling a trustworthy library function."

The author can be reached at goodhill (AT) xmission.com.

**1 **For this article I have ignored any issues
of leap seconds which occasionally effect the length of other days.
Most binary java.util.Dates do
not include leap seconds because the underlying hardware and OS does not provide
leap seconds.

**2** See the discussion in **The Best of Dates, The Worst Of Dates**.

**Last updated 2005-05-22 **