为什么在1971年11月1日之前将一小时添加到java.util.Date的日期?

时间:2009-08-06 10:49:04

标签: java datetime

以下代码似乎演示了java.util.Date中的一个错误,如果本地时钟设置为GMT且DST调整开启且时间早于1971年11月1日,则会添加一小时。我的第一个假设始终是我弄错了。任何人都可以看到什么是错的(或者这真的是一个Java错误)? 1971年11月1日有什么重要意义?

import java.text.SimpleDateFormat;
import java.util.Locale;
import java.util.TimeZone;

class JavaUtilDateBug
{
    private static void demo() throws Exception
    {
        // UK developers usually have the clock on their development machines set
        // to "Europe/London" (i.e. GMT with daylight saving). Set it explicitly 
        // here so readers in other countries can see the problem too.
        TimeZone.setDefault(TimeZone.getTimeZone("Europe/London"));
        Locale.setDefault(Locale.ENGLISH);

        SimpleDateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy");
        String strJan1st1970Expected = "Thu Jan 01 00:00:00 GMT 1970";
        String strJan1st1970Actual = dateFormat.parse(strJan1st1970Expected).toString();
        System.out.println("strJan1st1970Actual: " + strJan1st1970Actual); // -> "Thu Jan 01 01:00:00 GMT 1970"
        boolean jvmHasDateBug = !strJan1st1970Expected.equals(strJan1st1970Actual);
        System.out.println("jvmHasDateBug: " + jvmHasDateBug); // -> true

        // The anomaly only seems to affect times before 1 Nov 1971.
        final String strNov1st1971 = "Mon Nov 01 00:00:00 GMT 1971";
        assert strNov1st1971.equals(dateFormat.parse(strNov1st1971).toString());
    }

    public static void main(String[] args)
    {
        try
        {
            demo();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

我的Java环境:

  java version "1.6.0_13"
  Java(TM) SE Runtime Environment (build 1.6.0_13-b03)
  Java HotSpot(TM) Client VM (build 11.3-b02, mixed mode, sharing)

4 个答案:

答案 0 :(得分:21)

在1968年10月27日至1971年10月31日之间有一次英国标准时间的审判,我怀疑这是导致这个问题的原因。

这里有一些试验细节:

http://en.wikipedia.org/wiki/British_Summer_Time#Single.2FDouble_Summer_Time

1970年1月1日欧洲/伦敦的时区是英国标准时间(GMT + 1),因此当您使用java.text.SimpleDateFormat解析1970年1月1日00:00:00 GMT时它生成正确的纪元值相等到1970年1月01日01:00:00在BST。

然后,由于java.util.Date的蹩脚,当您致电java.util.Date.toString()时,它会使用 now 的当前本地的默认时区,该时区已更改为GMT和你得到1970年1月1日01:00:00 GMT。

答案 1 :(得分:13)

这是语言环境。来自http://en.wikipedia.org/wiki/British_Summer_Time

  

英国标准时间计划于1968年10月27日至1971年10月31日期间进行了试验,当时英国全年保持GMT + 1。

答案 2 :(得分:5)

我在Sun的bug数据库中找到了matching bug。似乎他们认为这是一个“历史不准确”(格式化显然应该产生“BST”作为时区而不是GMT - 小时将是正确的)并且不会修复它,因为内心深处,TimeZone实现无法处理地方切换时区名称。

作为解决方法,您可以明确将时区设置为GMT而不是“欧洲/伦敦”。然后问题就消失了。

答案 3 :(得分:0)

这不是错误。

当您使用BST时区解析此日期时,您已将默认时区设置为(GMT + 1) GMTJan 1 1970 00:00:00日期BST默认情况下,它始终根据您当前的时区显示时间(自动应用GMT的偏移量)。

在这种情况下它是GMT + 1,这就是为什么你的结果是一个小时的原因。