【问题标题】:Why does an hour get added on to java.util.Date for dates before Nov 1 1971?为什么 1971 年 11 月 1 日之前的日期会在 java.util.Date 中添加一个小时?
【发布时间】:2009-08-06 10:49:03
【问题描述】:

以下代码似乎演示了 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)

【问题讨论】:

  • 只有在您还设置了语言环境(否则日期解析失败)的情况下,您的演示程序才能在非英语机器上运行。
  • 谢谢,迈克尔。演示代码已更新。

标签: java datetime


【解决方案1】:

在 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 时,它会生成等于 Jan 的正确纪元值1970 年英国夏令时 01 01:00:00。

然后,由于java.util.Date 的糟糕之处,当您调用java.util.Date.toString() 时,它使用现在的当前本地默认时区,该时区已更改为格林威治标准时间,您将获得一月 1 日1970 年格林威治标准时间 01:00:00。

【讨论】:

  • 有趣。不过,仍然不清楚为什么它不是对称的 - 如果你输入“Thu Jan 01 00:00:00 GMT 1970”,你应该得到同样的回报。
  • 这不是 java.util.Date 的 toString() 的问题,当您使用与解析相同的 SimpleDateFormat 对其进行格式化时,行为并没有什么不同。请参阅我对 Sun 对此的回答。
  • 嘿 Michael - 看看 java.util.Date 的 normalize() 方法。它从 toString() 方法调用,并调用 TimeZone.getDefaultRef() 来获取时区。这看起来像原因对吧?
  • 这只是获取默认时区,这是 David 在他的脚本中设置的第一件事,SimpleDateFormat 也隐式使用了该时区。
  • 有趣 - 不知道。请注意,那时我还没有出生,所以我确实有一个借口。 :-)
【解决方案2】:

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

英国标准时间方案在 1968 年 10 月 27 日至 1971 年 10 月 31 日期间试行,当时英国全年保持 GMT+1。

【讨论】:

  • 呸。当我收到你们两个的通知时,我已经回答了一半。
【解决方案3】:

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

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

【讨论】:

  • 错误数据库中似乎不再提供该错误。
【解决方案4】:

这不是错误。

您已将默认时区设置为BST,即(GMT + 1)GMT 日期Jan 1 1970 00:00:00,当您使用BST 作为默认时区解析此日期时,它始终根据您的当前时区(自动应用与GMT 的偏移量)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多