将 SimpleDateFormatter 与时区一起使用时出现意外结果

Unexpected result when using SimpleDateFormatter with a timezone

我的目标是针对给定时区解析格式为 yyyy-MM-dd hh:mm:ss.SSS 的日期字符串,仅使用 Java 6,不使用任何外部库。我的第一种方法是使用时区配置 SimpleDateFormatter。但是,我无法理解结果。看看下面的代码:

List<String> zones = Arrays.asList("UTC", "CET", "Europe/London", "Europe/Berlin");

for(String zone: zones) {
  SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
  df.setTimeZone(TimeZone.getTimeZone(zone));
  Date result =  df.parse("1970-01-01 00:00:00.000");
  System.out.println(zone + ": " + result.getTime()); 
}

输出结果如下:

UTC: 0
CET: -3600000
Europe/London: -3600000
Europe/Berlin: -3600000

前两个结果符合预期。在 UTC 中,unix 纪元恰好从零毫秒开始,与 CET 相差一小时。

我不明白伦敦和柏林的价值观。由于伦敦的毫秒等于 CET 而不是 UTC 的毫秒,我首先假设考虑了夏令时(因为目前北半球是夏季,而伦敦的夏季是 UTC+1,等于 CET)。但是,为什么柏林的价值相同?不应该是 UTC+2(或者 CET+1 如果你愿意的话)?


我的问题:

结果是正确的,因为那是London and Berlin在1970年使用的偏移量(都使用+01:00)。

它与夏令时无关,因为如今这些国家/地区的夏令时发生在三月和十月。 实际上,有人可能会争辩说,从 1968 年到 1971 年,伦敦处于 "long" 夏令时期间,因为在整个期间偏移量为 +01:00

这只是时区的性质:时区由政府和法律定义,各个政客可以出于任何原因更改其国家/地区使用的时差。

在上面的相同链接中,您可以看到柏林在 1980 年才采用 DST,而伦敦在 1971 年将偏移量更改为零(GMT)。


PS: 正如评论中所讨论的那样,像 CET 这样的短名称是 ambiguous and not standard (for lots of them, there's more than one timezone that uses the same abbreviation). Always prefer to use IANA timezones names(格式总是 Region/City,如 America/Sao_PauloEurope/Berlin).

一些名称(例如 CET)被识别并设置为任意默认值 - 主要是由于复古兼容性(或糟糕的设计)问题 - 但它通常以意想不到的方式完成。尽可能避免使用这样的短名称:像 Europe/Berlin 这样的名称更加清晰,没有歧义。