令人困惑的测试失败 - 夏令时

时间:2015-11-02 16:13:42

标签: java datetime dst

在Jenkins的每晚建造中,我们的一次测试在凌晨2:00:12失败了。经过一段时间调试和改变我的电脑的系统时间,我很困惑。然后我编写了以下测试(模拟问题),但失败了,但我无法理解原因。我试过谷歌,但没有发现任何类似的东西 任何人都可以解释为什么最后一个断言失败了吗?

@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();
}

(在布鲁塞尔时区,夏令时结束于25-10-15凌晨3点。时钟然后跳回一小时。)

1 个答案:

答案 0 :(得分:7)

如果您在每一步都打印出firstsecond,就会得到以下内容:

你的第一场比赛是

Sun Oct 25 00:59:00 CEST 2015
Sun Oct 25 01:01:00 CEST 2015

完全符合预期。在中欧夏令时期间,两次,相隔两分钟。

第二场比赛变得有趣。你在每个日期增加了两个小时:

Sun Oct 25 02:59:00 CEST 2015
Sun Oct 25 02:01:00 CET 2015

现在两次跨越DST切换。第一次是夏季时间,2:59;第二次是在标准时间,即2:01。

当你向它添加两天时,看起来Java会忘记夏令时:

Tue Oct 27 02:59:00 CET 2015
Tue Oct 27 02:01:00 CET 2015

2:59和2:01,完全一样......这可能是两天后的日历,但第一次肯定不比第二步晚48小时!

如果您将最终的添加内容更改为

    first = add(first, Calendar.HOUR_OF_DAY, 48);
    second = add(second, Calendar.HOUR_OF_DAY, 48);
然后问题就消失了:

Tue Oct 27 01:59:00 CET 2015
Tue Oct 27 02:01:00 CET 2015

我的猜测是Java设计师必须对N天后的预期行为做出一些猜测"意味着什么时候跨越DST切换。