【问题标题】:Why negative DST time has standard zone name?为什么负 DST 时间有标准区域名称?
【发布时间】:2019-06-23 13:54:43
【问题描述】:

对于具有负 DST 偏移的特定历史日期,我得到了错误的时区名称。

时区数据库 (tzdata) 的更新在 1946 年 12 月 1 日至 1947 年 2 月 23 日期间为欧洲/布拉格区引入了负 DST。

这是欧洲/布拉格的 tzdata 来源:

# We know of no English-language name for historical Czech winter time;
# abbreviate it as "GMT", as it happened to be GMT.

...

            1:00    Czech   CE%sT   1946 Dec  1  3:00
# Vanguard section, for zic and other parsers that support negative DST.
            1:00    -1:00   GMT 1947 Feb 23  2:00
# Rearguard section, for parsers that do not support negative DST.
#           0:00    -   GMT 1947 Feb 23  2:00

这个新数据库自 u181 以来就在 Java 8 中。

在指定时间段内使用时间时,我得到错误的时区名称为“CET”/“中欧时间”,而不是 tzdata 中所述的 GMT。

Long timeInMilis = Long.parseLong("-725328000000");
String pattern = "yyyy-MM-dd HH:mm:ss zzz";
TimeZone.setDefault(TimeZone.getTimeZone(("Europe/Berlin")));
System.out.println(new SimpleDateFormat(pattern).format(new Date(timeInMilis)));
TimeZone.setDefault(TimeZone.getTimeZone(("Europe/Prague")));
System.out.println(new SimpleDateFormat(pattern).format(new Date(timeInMilis)));

结果是

1947-01-07 01:00:00 CET
1947-01-07 00:00:00 CET

第一行是柏林时区,第二行是布拉格时区。 两者都说这是 CET,但对于布拉格来说这是错误的。它应该是时区数据库中提到的 GMT

【问题讨论】:

  • 原因可能是区域名称不是直接取自 tzdata 中适用的行,而是取自 TimeZone 对象,它不知道日期是什么。如果您认为这种行为是错误的,您可能需要提交一个错误 - 尽管它可能只会针对 java.time 类进行修复。
  • 注意Long.parseLong("-725328000000")应该写成-725328000000L
  • 或者更好的是725_328_000_000L(也是@VGR)
  • 我建议你不要使用TimeZoneSimpleDateFormatDate。这些类设计不佳且早已过时,SimpleDateFormat 特别是出了名的麻烦。而是使用InstantZoneIdZonedDateTimeDateTimeFormatter,均来自java.time, the modern Java date and time API

标签: java timezone


【解决方案1】:

至少就我在 OpenJDK 的这个问题的历史上所见......

https://bugs.openjdk.java.net/browse/JDK-8195595?page=com.atlassian.jira.plugin.system.issuetabpanels%3Aall-tabpanel

...到目前为止,OpenJDK 通过使用 tzdata 的“后卫”版本来避免处理负 DST,该版本没有负 DST(显然很快就会消失的选项)。

我怀疑 Oracle 的 Java 到目前为止也一直在避免处理负 DST。

无论如何,我认为 Java 的时区实现不能很好地处理这些时区缩写。我尝试了这段示例代码:

    SimpleDateFormat  format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzz");

    format.setTimeZone(TimeZone.getTimeZone(("Europe/Prague")));

    for (int date = 1; date <= 28; ++date) {
      System.out.println(format.format(new GregorianCalendar(1947, 1, date, 0, 0).getTime()));
    }

...在假定的过渡日期前后,该名称保持为“CET”。

...
1947-02-20 05:00:00 CET
1947-02-21 05:00:00 CET
1947-02-22 05:00:00 CET
1947-02-23 06:00:00 CET
1947-02-24 06:00:00 CET
1947-02-25 06:00:00 CET
1947-02-26 06:00:00 CET
...

如果我没记错的话,Java 的时区实现根本不保留这些缩写更改的历史记录,它只是对时区偏移更改的转换时间进行编码。显示的缩写是根据当前而非历史标准呈现的。

编辑:我之前读错了 tzdata 并且误解了它的含义!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 2016-02-24
    • 2012-04-25
    • 2012-05-09
    • 2016-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多