tl;博士
Daylight Saving Time (DST) 的定义在 1980 年和 2016 年之间发生了变化。
之前的夏令时结束于9 月的最后一个星期日,后来改为结束于10 月的最后一个星期日。
详细解答
难题中缺少的部分是知道计算中使用的特定时区。 您的问题和示例代码未能准确告诉我们使用了哪些时区。我在此处的讨论假设您使用的时区类似于 Europe/Berlin 的时区(基于您使用的明显本地化为德语的文本语言),因为它对DST 的定义发生了变化。
CET 和 CEST 实际上不是时区。这样的缩写不是标准化的,甚至也不是唯一的。 避开它们。
改为使用tz database 中定义的proper time zone names。 true time zone 是 offset-from-UTC 加上一组用于处理过去、现在和未来异常的规则,例如夏令时 (DST)。
时区规则会发生变化,而且变化频繁。无聊的政客,我想。
例如,Europe/Berlin 在 1980 年更改为在 9 月的最后一个星期日结束 DST。因此,DST 不适用于您 1980 年 10 月的日期。自 1996 年以来,欧盟规则适用,将 DST 延长至 10 月的最后一个星期日,而不是 9 月。因此,DST 确实适用于 2016 年 10 月 10 日的日期。
问题中的代码使用月份“9”,这实际上表示“10”,十月。旧的java.util.Date 类的许多问题之一是它通过从零开始的计数来计算月份,0 = 一月。避免使用旧的日期时间类的众多原因之一。相比之下,在 java.time 中,10 月份的月份数确实是 10,正如您所期望的那样,您可以使用 Month 枚举中的常量来更清楚。
顺便说一句,java.util.Date 中另一个糟糕的设计选择是当问题中的constructing a Date object as you did 时,应用了您的 JVM 当前的默认时区,并将结果调整回 UTC。这进一步使您的问题复杂化,因为您在运行代码时没有报告正在使用的时区。
顺便说一句,与几乎所有开发平台一样,JavaScript 对日期时间工作的支持很差。尽可能尝试使用 Java 及其内置的java.time 框架。见Oracle Tutorial。您可以在以下示例代码中见证 java.time 的运行。 Europe/Berlin 是 1980 年和 2016 年的 10 月 10 日。
ZoneId zoneId = ZoneId.of ( "Europe/Berlin" );;
ZonedDateTime zdt_1980 = ZonedDateTime.of ( 1980 , Month.OCTOBER.getValue () , 10 , 0 , 0 , 0 , 0 , zoneId );
long seconds_1980 = zdt_1980.toEpochSecond ();
ZonedDateTime zdt_2016 = ZonedDateTime.of ( 2016 , Month.OCTOBER.getValue () , 10 , 0 , 0 , 0 , 0 , zoneId );
long seconds_2016 = zdt_2016.toEpochSecond ();
转储到控制台。
System.out.println ( "zoneId: " + zoneId );
System.out.println ( "zdt_1980: " + zdt_1980 + " | seconds_1980: " + seconds_1980 );
System.out.println ( "zdt_2016: " + zdt_2016 + " | seconds_2016: " + seconds_2016 );
您可以在结果中看到,与 UTC 的偏移量从过去比 UTC 提前一小时 (+01:00) 变为现在比 UTC 提前两小时 (+02:00)。区别在于DST的重新定义。
所以,这就解释了为什么您在 1980 年获得了“CET”,而在 2016 年获得了“CEST”。您在 2016 年获得的 CEST 中的 S 表示“夏季”,而“夏令时”表示 DST。 2016 年,十月的大部分时间都在“夏令时”(DST)。在 1980 年,10 月 在 DST/"Summer Time"/"CEST" 中。
zoneId:欧洲/柏林
zdt_1980: 1980-10-10T00:00+01:00[欧洲/柏林] | seconds_1980: 339980400
zdt_2016: 2016-10-10T00:00+02:00[欧洲/柏林] |秒_2016:1476050400