java - 使用 TimeZone 和 SimpleDateFormat 进行日期解析/格式化会在 DST 开关周围产生不同的结果

标签 java timezone simpledateformat

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

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

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

使用 Sun 的 SimpleDateFormat 使我们的时间相差一个小时(这可能与夏令时有关)。将默认时区设置为 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);
}

最佳答案

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

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

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

我猜测 IBM 时区“有效”的原因是它可能使用美国更改其 DST 转换之前的旧时区数据。尝试使用 3 月 28 日,这是我认为它否则的时间 - 您可能会发现测试以与 IBM 区域相同的方式失败,但与 Sun 区域不同:)(作为Sun 区域不会将其视为 DST 转换。)

关于java - 使用 TimeZone 和 SimpleDateFormat 进行日期解析/格式化会在 DST 开关周围产生不同的结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2356672/

相关文章:

r - 如何从POSIXct和POSIXlt对象中提取正确的时区?

android - 如何获得星期几的本地化

java - SimpleDateFormat 不一致的解析错误

java - 字符串日期 + 日期对象 Java 的时间

java - 哪个是用于数字和字符串的正确正则表达式?

java - 为什么我不能在 Eclipse 中的某些 Java 源文件(插件 jar 的只读源)中设置断点?

php - 使用时区数据来锻炼本地用户时间

java - 无法从 Android 设备获取所有歌曲

java - com.mysql.jdbc.exceptions.jdbc4.CommunicationsException : Communications link failure

reporting-services - SQL Reporting Services 2005本地时区