Recently a needed to get the number of days between two dates in Java.
Easy, right? Quite a few pages & articles suggest, and I admit my first iteration too, was:
Calendar firstDay = new GregorianCalendar(2006, Calendar.FEBRUARY, 3)
Calendar lastDay = new GregorianCalendar(2006, Calendar.JULY, 17);
static final long DAY_MS = 1000 * 60 * 60 * 24;
int days = (lastDay.getTime().getTime() - firstDay.getTime().getTime()) / DAY_MS;
It turns out this is WRONG, for example for the two dates given (days == 163, but shold be 164!) - some rounding error. This will round correctly, as some better Web pages explain:
double daysDouble = lastLong - firstLong;
int days = (int) Math.round(daysDouble / DAY_MS); // = 164
but using the Calendar API provides a clearer, more reable and most importantly correct version, too:
assert firstDay.get(Calendar.YEAR) == lastDay.get(Calendar.YEAR); // Assumption
int days = lastDay.get(Calendar.DAY_OF_YEAR) - firstDay.get(Calendar.DAY_OF_YEAR);
Or, for more calculations of this kind, consider http://joda-time.sourceforge.net/
I don't think this will work if the dates are in different years.
ReplyDeleteAbsolutely, you are right; that's why I'd put that assert with // assumption in the code snippet above.
ReplyDeleteI have run into the same problem. My date ran is one hour less than expected. My date range like your spanned the start of daylight savings. I think that is the problem. You can't assume a constant MS/Day. The first day of daylight savings has only 23 hours.
ReplyDeleteTony
What about this:
ReplyDeletestatic final long ONE_HOUR = 60 * 60 * 1000L;
public long daysBetween(Date startDate, Date endDate) {
return ((endDate.getTime() - startDate.getTime() + ONE_HOUR) / (ONE_HOUR * 24));
}
or another one a bit different but same meaning:
private static final long MILISECONDS_PER_DAY = 24 * 60 * 60 * 1000;
public int getDaysBetweenDates(Date startDate, Date endDate) {
long diff = endDate.getTime() - startDate.getTime();
int days = (int) Math.floor(diff / MILISECONDS_PER_DAY);
return Math.abs(days);
}
David N. :)
here's a rather brutal way to do this :)
ReplyDeletepublic static int getDays(Calendar from, Calendar to)
{
int cnt = 0;
while (from.before(to)) {
cnt++;
if (from.getActualMaximum(DATE) == from.get(DATE)) {
from.roll(MONTH, true);
}
if (from.getActualMaximum(MONTH) == from.get(MONTH)) {
from.roll(YEAR, true);
}
from.roll(DATE, true);
}
return ctn;
}