On a nightly build of Jenkins, one of our tests failed at 2:00:12am. After some time debugging and changing the systemtime of my computer, I was very confused. Then I wrote the following test (simulating the issue), which fails, but I'm unable to understand why. I tried Google, but found nothing similar.
Can anyone explain why the last assert fails?
@Test
public void testFirstBeforeSecond_atDayLightSavingTime() throws ParseException {
Date first = new SimpleDateFormat("dd-MM-yyyy HH:mm").parse("25-10-2015 00:59");
Date second = new SimpleDateFormat("dd-MM-yyyy HH:mm").parse("25-10-2015 01:01");
assertThat(first.before(second), is(true)); // Ok, as expected
first = add(first, Calendar.HOUR_OF_DAY, 2);
second = add(second, Calendar.HOUR_OF_DAY, 2);
assertThat(first.before(second), is(true)); // Ok, as expected
first = add(first, Calendar.DAY_OF_YEAR, 2);
second = add(second, Calendar.DAY_OF_YEAR, 2);
assertThat(first.before(second), is(true)); // Fails?
}
private Date add(Date date, int field, int amount) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("Europe/Brussels"));
calendar.setTime(date);
calendar.add(field, amount);
return calendar.getTime();
}
(In Brussels time zone, daylight saving time ended on 25-10-15 at 3am. The clock then jumped back one hour.)
If you print out first
and second
at each step of the way, here's what you get:
Your first matchup is
Sun Oct 25 00:59:00 CEST 2015
Sun Oct 25 01:01:00 CEST 2015
which is exactly as expected. Two times, two minutes apart, during Central European Summer Time.
Second matchup gets interesting. You added two hours to each date:
Sun Oct 25 02:59:00 CEST 2015
Sun Oct 25 02:01:00 CET 2015
Now the two times span the DST switchover. First time is during summer time, 2:59; second time is during standard time, at 2:01.
When you add two days to it, it looks like Java forgets all about summer time:
Tue Oct 27 02:59:00 CET 2015
Tue Oct 27 02:01:00 CET 2015
2:59 and 2:01, exactly as it was ... this might be two days later by the calendar, but the first time is certainly not 48 hours later than step two!
If you change the final sets of additions to
first = add(first, Calendar.HOUR_OF_DAY, 48);
second = add(second, Calendar.HOUR_OF_DAY, 48);
then the problem goes away:
Tue Oct 27 01:59:00 CET 2015
Tue Oct 27 02:01:00 CET 2015
My guess is that the Java designers had to make some guesses about the expected behaviour of what "N days later" meant when that spans a DST switchover.