3

我在 Google 和 Stack Overflow 上浏览了多篇关于 TimeZone 和 SimpleDateFormat 的帖子,但仍然不明白我做错了什么。我正在处理一些遗留代码,并且有一个方法 parseDate,它给出了错误的结果。

我附上了我正在尝试使用的示例 JUnit 来调查问题。

第一种方法(testParseStrangeDate_IBM_IBM)使用 IBM 的实现来格式化parseDate方法的输出。Sun 实现的第二种格式输出。

使用 Sun 的 SimpleDateFormat 使我们的时间相差一个小时(这可能与夏令时有关)。将默认 TimeZone 设置为 IBM 的实现修复了 parseDate方法(只需取消注释 setupDefaultTZ 方法中的 3 行)。

我确定这不是错误,但我做错了什么。

@Test
public void testParseStrangeDate_IBM_IBM() {
    setupDefaultTZ();

    Calendar date = parseDate("2010-03-14T02:25:00");
    com.ibm.icu.text.SimpleDateFormat dateFormat = new com.ibm.icu.text.SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");

    // PASSES:
    assertEquals("2010-03-14 02:25:00", dateFormat.format(date.getTime()));
}

@Test
public void testParseStrangeDate_SUN_SUN() {
    setupDefaultTZ();

    Calendar date = parseDate("2010-03-14T02:25:00");
    java.text.SimpleDateFormat dateFormat = new java.text.SimpleDateFormat(
            "yyyy-MM-dd HH:mm:ss");

    // FAILS:
    assertEquals("2010-03-14 02:25:00", dateFormat.format(date.getTime()));
}

public static Calendar parseDate(String varDate) {
    Calendar cal = null;
    try {
        // DOES NOT MAKE ANY DIFFERENCE:
        // com.ibm.icu.text.SimpleDateFormat simpleDateFormat = new
        // com.ibm.icu.text.SimpleDateFormat(
        // "yyyy-MM-dd'T'HH:mm:ss");
        java.text.SimpleDateFormat simpleDateFormat = new java.text.SimpleDateFormat(
                "yyyy-MM-dd'T'HH:mm:ss", Locale.US);
        Date date = simpleDateFormat.parse(varDate);
        cal = GregorianCalendar.getInstance();
        cal.setTimeInMillis(date.getTime());
        System.out.println("CAL: [" + cal + "]");
    } catch (ParseException pe) {
        pe.printStackTrace();
    }
    return cal;
}

private void setupDefaultTZ() {
    java.util.TimeZone timeZoneSun = java.util.TimeZone.getTimeZone("America/Chicago");
    java.util.TimeZone.setDefault(timeZoneSun);

    // UNCOMMENTING THIS ONE FIXES SUN PARSING ??
    // com.ibm.icu.util.TimeZone timeZoneIbm = com.ibm.icu.util.TimeZone
    // .getTimeZone("America/Chicago");
    // com.ibm.icu.util.TimeZone.setDefault(timeZoneIbm);

    Locale.setDefault(Locale.US);
}
4

1 回答 1

2

问题是,您指定了一个不存在的时间。时钟向前移动,使得凌晨 2 点变成凌晨 3 点 - 凌晨 2 点 25 分永远不会发生。

现在,这里可能发生的事情有多种选择。在野田时代,我相信我们会抛出一个异常(无论如何这是计划);我相信Joda Time(比 Date/Calendar/SimpleDateFormat 更好的 Java API - 如果可能的话,您应该考虑迁移到它)会给您凌晨 3:25,即转换后 25 分钟。

当您获得一个由于 DST 转换而无法实现的日期/时间组合时,您希望发生什么?在这种情况下,很难确定您所说的“错误”结果是什么意思。我会说你的单元测试有些缺陷 - 没有可能的时间应该格式化为那个时间。

我对 IBM 时区为什么“有效”的猜测是它可能使用旧时区数据,从美国更改其 DST 过渡开始。尝试使用 3 月 28 日,我认为这是其他情况 - 您可能会发现 IBM 区域的测试以相同的方式失败,但 Sun 区域的测试失败 :) (因为 Sun 区域不会考虑它是 DST 过渡。)

于 2010-03-01T15:21:39.643 回答