Java SimpleDateFormat在10月时钟更改日的重复时间段内会产生不同的结果

时间:2012-03-01 17:57:49

标签: java parsing simpledateformat

我正在研究Java中的SimpleDateFormat。

我想格式化日期字符串并将其转换为日期/日历,然后将生成的日期/日历格式化回字符串。这是一个超过10月时钟变化的日期时间,你当天有两个03:00。十月时钟变换期的时间应为:

**更新我已将时间从01:00更改为03:00,当天应该有2次**

  • 2012-10-28 02:00:00 CEST
  • 2012-10-28 02:30:00 CEST
  • 2012-10-28 02:00:00 CET
  • 2012-10-28 02:30:00 CET
  • 2012-10-28 03:00:00 CET

转换2012-10-28 01:00:00 CET到日期/日历然后回到字符串导致问题。转换后的字符串是2012-10-28 02:00:00 CEST - 它不存在。

以下代码将复制此问题:

public class DatesAndTimesStackOverflow {

final static SimpleDateFormat sdf;
final static TimeZone tz;
static {
    tz = TimeZone.getTimeZone( "Europe/Paris" );
    sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");
    sdf.setTimeZone(tz);
}

public static void main(String[] args) {

    // october clock change should be the following:
    outputDateInfo("2012-10-28 02:00:00 CEST");
    outputDateInfo("2012-10-28 02:30:00 CEST");
    outputDateInfo("2012-10-28 02:00:00 CET");
    outputDateInfo("2012-10-28 02:30:00 CET");
    outputDateInfo("2012-10-28 03:00:00 CET");
    outputDateInfo("2012-10-28 03:30:00 CET");
    outputDateInfo("2012-10-28 04:00:00 CET");
}


private static void outputDateInfo(String theDate) {
    try {
        output("------------------------------------------------------------------------------");
        Date d = sdf.parse(theDate);
        Calendar c = GregorianCalendar.getInstance(tz);
        c.setTimeInMillis(d.getTime());
        TimeZone tzCal = c.getTimeZone();

        output("String:                       " + theDate);
        output("");
        output("Date:                         " + d);                   // toString uses current system TimeZone
        output("Date Millis:                  " + d.getTime());
        output("Cal Millis:                   " + c.getTimeInMillis());
        output("Cal To Date Millis:           " + c.getTime().getTime());
        output("Cal TimeZone Name:            " + tzCal.getDisplayName());
        output("Cal TimeZone ID:              " + tzCal.getID());
        output("Cal TimeZone DST Name:        " + tzCal.getDisplayName(true, TimeZone.SHORT));
        output("Cal TimeZone Standard Name:   " + tzCal.getDisplayName(false, TimeZone.SHORT));
        output("In DayLight:                  " + tzCal.inDaylightTime(d));

        output("");
        output("Day Of Month:                 " + c.get(Calendar.DAY_OF_MONTH));
        output("Month Of Year:                " + c.get(Calendar.MONTH));
        output("Year:                         " + c.get(Calendar.YEAR));

        output("Hour Of Day:                  " + c.get(Calendar.HOUR_OF_DAY));
        output("Minute:                       " + c.get(Calendar.MINUTE));
        output("Second:                       " + c.get(Calendar.SECOND));

        // check to see if this converts back to correct string
        String reformat = sdf.format(c.getTime());
        if( reformat.equals(theDate) ) {
            output("ReConvert:                    " + reformat + " OK");
        } else {
            output("ReConvert:                    " + reformat + " <-------- Error.  The converted date is different");
        }

    } catch (ParseException ex) {
        output("Cannot parse this date");
    }
}

private static void output(String message) {
    System.out.println(message);
}
}

我不认为这是我的例子的问题。希望它在Java中不是问题。如果不是我编码的方式,是否有合理的解释?

1 个答案:

答案 0 :(得分:6)

这是对的。有这样的时间是2:00(或3)CEST。欧洲/巴黎包含两个时区,CET和CEST。它们总是相隔一小时并且都是连续的(时区的UTC偏移永远不会改变,日历会切换时区)。

还要注意,倒退发生在早上3点,而不是早上1点!如果你把时间改为3,你应该看到它翻转,解析3: 00CET输入产生3:00CET输出,但解析3:00CEST输入,产生2:00CET输出,如预期的那样。

巴黎凌晨3点,当前时间从CEST 3:00变为CET 2:00。当您指定2012年10月28日3:00 CEST作为输入时,它将最终输出上午2:00 CET,这是相同的实际时间点,因为这就是巴黎墙上的时钟所说的!

-

我认为对于CET与机器意义的“人”意义存在一些混淆。对于巴黎的“CET”,意思是“冬季的+1小时UTC和夏季的+2小时UTC”。但是,当您看到解析器打印的输出时,CET表示始终为+1小时。因此,当您在10月28日“第一个”凌晨3:00之前打印巴黎时,解析器将输出为CEST。当您打印10月28日“第一”凌晨3点之后发生的巴黎时间时,它会说CET。

在夏令时,巴黎人将体验02:59 CET(机器意义)和02:59 CEST,而不是“02:59 CET两次”,这可能是一种更人性化的理解。它们都是存在的有效时间。