【问题标题】:Difference Timezones Browser and Java不同时区浏览器和 Java
【发布时间】:2016-08-22 09:20:21
【问题描述】:

我对在同一时区的同一台机器上运行的浏览器 (JS) 和 Java 中的日期/时间/时区差异有疑问。我知道系统应该就时区达成一致(主要是UTC,使用Date.UTC)以避免此类问题。不过我认为这个例子应该可以正常工作。

为此,我使用浏览器 (Chrome) 创建了一些日期,并使用相同的millis 使用 Java 创建了一个日期。

这是一个我不明白的例子。请帮我理解。

Chrome (JavaScript):

new Date(1980,9,10,0,0,0,0) Fri Oct 10 1980 00:00:00 GMT+0200 (Mitteleuropäische Sommerzeit) The millis are: 339976800000

Java:

new Date(339976800000l) Thu Oct 09 23:00:00 CET 1980

请注意,Java 应用 CET,而 JavaScript 应用 CEST。

【问题讨论】:

  • 23:00 CET == 00:00 CEST(冬夏时差)。
  • 请仔细阅读问题,我想知道为什么Java在这种情况下使用CET而不是CEST。
  • 请提供您在 Java 中使用的实际代码。 java.util.Date 没有带 7 个参数的构造函数;此外,您需要减去年份和月份的偏移量。另外,请在两种环境中显示您配置的时区。
  • 谢谢,将编辑。实际上我只是将millis复制到Java。
  • 1980 年 10 月 9 日是冬季。

标签: javascript java datetime


【解决方案1】:

tl;博士

Daylight Saving Time (DST) 的定义在 1980 年和 2016 年之间发生了变化。

之前的夏令时结束于9 月的最后一个星期日,后来改为结束于10 月的最后一个星期日

详细解答

难题中缺少的部分是知道计算中使用的特定时区。 您的问题和示例代码未能准确告诉我们使用了哪些时区。我在此处的讨论假设您使用的时区类似于 Europe/Berlin 的时区(基于您使用的明显本地化为德语的文本语言),因为它对DST 的定义发生了变化。

CETCEST 实际上不是时区。这样的缩写不是标准化的,甚至也不是唯一的。 避开它们。

改为使用tz database 中定义的proper time zone namestrue time zoneoffset-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

【讨论】:

  • 非常感谢您提供的所有信息。上面的代码仅用于演示目的。客户端和服务器在同一时区运行。所以实际的问题是 JS 和 Java 以不同的方式处理过去的日期。 JS 仅应用此处描述的当前 DST 规则stackoverflow.com/questions/16946002/…
  • @chris1069603 实际上,除非您确定在 JavaScript 和 Java 中应用了哪个时区,否则无法真正诊断出您的情况。请在这两种情况下添加代码以获取和报告时区。在那之前,你只是在猜测和做出假设。在 Java 中,您可以调用 ZoneId.systemDefault()TimeZone.getDefault()。对于 JavaScript,我不知道。
  • 确实是欧洲/柏林。附加的链接很好地解释了 Javascript 行为。我根据您的输入对问题进行了一些编辑,以使问题更清楚。当我阅读 cmets 时,我觉得我一开始就失败了。对不起。希望我们可以使它对其他人有用。对我来说,意识到 Java 和 JS 应用不同的规则是一个很大的惊喜
猜你喜欢
  • 1970-01-01
  • 2016-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多