Java 为什么负DST时间有标准区域名称?

Java 为什么负DST时间有标准区域名称?,java,timezone,Java,Timezone,对于DST偏移量为负的特定历史日期,我得到了错误的时区名称 时区数据库(tzdata)的更新在1946-12-01至1947-02-23期间为欧洲/布拉格引入了负DST 这是欧洲/布拉格的数据来源: # We know of no English-language name for historical Czech winter time; # abbreviate it as "GMT", as it happened to be GMT. 这个新数据库是从u181开始使用Java8的 当

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

时区数据库(tzdata)的更新在1946-12-01至1947-02-23期间为欧洲/布拉格引入了负DST

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

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

这个新数据库是从u181开始使用Java8的

当在指定时间段内使用时间时,我得到了错误的时区名称“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,正如时区数据库中提到的,至少就我在OpenJDK发行历史中所看到的那样

…到目前为止,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()));
    }
如果我没记错的话,Java的时区实现根本不保留这些缩写变化的历史记录,它只是为时区偏移量的变化编码转换时间。显示的缩略语是根据当前而非历史标准呈现的


编辑:我以前读错了tzdata,对它的意思误解了

原因可能是区域名称不是直接取自tzdata中的适用行,而是取自TimeZone对象,它不知道日期是什么。如果您认为这种行为是错误的,那么您可能需要提交一个bug-尽管它很可能只针对
java.time
类进行修复。请注意
Long.parseLong(“-725328000000”)
应该写成
-725328000000L
。或者更好的是
725_328_000_000L
(也可以是@VGR)我建议您不要使用
时区
简化格式
日期
。这些类设计得很糟糕,而且很早就过时了,
SimpleDateFormat
尤其是出了名的麻烦。而是使用
Instant
ZoneId
ZonedDateTime
DateTimeFormatter
,所有这些都来自。
    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()));
    }
...
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
...