Java 为什么日期在不同的时区以相同的毫秒数变化?

Java 为什么日期在不同的时区以相同的毫秒数变化?,java,javascript,date,timezone,primefaces-extensions,Java,Javascript,Date,Timezone,Primefaces Extensions,我们知道java.util.Date的getTime方法返回自1970年1月1日00:00:00 GMT以来的毫秒数,由这个日期对象表示 我注意到一个奇怪的情况如下 系统时区为:(UTC+02:00)伊斯坦布尔 Date currentDate = new Date(); System.out.println(currentDate .getTime()); System.out.println(currentDate); Java控制台输出: console.log(new Date(136

我们知道java.util.Date的getTime方法返回自1970年1月1日00:00:00 GMT以来的毫秒数,由这个日期对象表示

我注意到一个奇怪的情况如下

系统时区为:(UTC+02:00)伊斯坦布尔

Date currentDate = new Date();
System.out.println(currentDate .getTime());
System.out.println(currentDate);
Java控制台输出:

console.log(new Date(1360753217219));
console.log(new Date(1360753217219));
1360753217219

2013年2月13日星期三13:00:17兽医


然后我的javascript插件正在使用下面这样的长对象

Javascript:

console.log(new Date(1360753217219));
console.log(new Date(1360753217219));
浏览器控制台输出:

console.log(new Date(1360753217219));
console.log(new Date(1360753217219));
日期{2013年2月13日星期三13:00:17 GMT+0200(土耳其标准时间)}


不过,这一切都没关系!将我的本地时区更改为(UTC-04:30)加拉加斯后,情况和小时的更改如下,以相同的毫秒数进行


Javascript:

console.log(new Date(1360753217219));
console.log(new Date(1360753217219));
浏览器控制台输出:

console.log(new Date(1360753217219));
console.log(new Date(1360753217219));
日期{2013年2月13日星期三06:30:17 GMT-0430(委内瑞拉标准时间)}

有人能解释一下吗?那是js bug吗?或者更重要的是,我应该如何在java端处理这个问题,以便在js端的不同时区以相同的毫秒数获得相同的日期


谢谢

不是bug,时区就是这样工作的

如果你现在给委内瑞拉的人打电话,问他现在几点了,他会告诉你现在几点了 比土耳其时间早6.5小时(根据您的示例)

正如您所提到的,您正在处理的数字表示自1970年00:00:00GMT以来的毫秒数,就在同一秒,加拉加斯的时间是31.12.1969 19:30GMT-0430

因此,无论多晚几秒,委内瑞拉的时间仍将比格林尼治标准时间早4:30小时

如果使用相同的输入(毫秒),则无法在不同的时区获得完全相同的日期,因为这样做完全是错误的


如果希望得到相同的结果,可以将时区差异(本例中为6.5小时)添加到输出中。按照德雷德尔博士的建议,你可能不应该弄乱毫秒。

毫秒是时区不可知的。自1970年1月1日格林威治标准时间以来,时间是以绝对值来衡量的。因此,我们的想法是,你得到毫秒数,然后计算出给定时区的本地时间。如果你仔细想想,这是有道理的。自1970年以来经过的毫秒数是相同的,无论您身在何处

这会让人有点困惑,但不要为了适应时区而胡思乱想。每个日期库都有将毫秒戳转换为特定于时区的本地时间的机制

因此,如果您的具体问题是如何在服务器和客户机之间有效地传递日期(您使用的语言并不重要),那么答案是来回传递毫秒,并在任意一侧计算出您所谈论的全局特定时间是完全安全的,如果这对你当时正在做的事情很重要。

tl;博士 2013-02-13T11:00:17.219Z

2013-02-13T13:00:17.219+02:00[欧洲/伊斯坦布尔]

2013-02-13T06:30:17.219-04:30[美洲/加拉加斯]

使用java.time 您使用的是与最早版本的Java捆绑在一起的麻烦的旧日期时间类。它们现在是遗留的,被java.time类所取代,java.time类是任何平台上最好的日期时间库

从(1970-01-01T00:00:00Z)中自1970年初开始的毫秒数开始。其他人指出,您可能无法理解一个历元参考日期有一个时区,而这个历元的时区是UTC,偏移量为零小时。所有其他偏移量均根据此偏移量进行测量,即UTC之前或之后的小时数和分钟数

该类表示时间线上的一个时刻,分辨率为(小数点的九(9)位)

instant.toString():2013-02-13T11:00:17.219Z

如果你想通过某个特定区域的镜头看到同一时刻,请应用时区

ZoneId zAmerica_Caracas = ZoneId.of( "America/Caracas" ) ;
ZonedDateTime zdtAmerica_Caracas = zdtEurope_Istanbul.withZoneSameInstant( zAmerica_Caracas ) ;
时区是特定区域使用的偏移的过去、现在和未来更改的历史

大陆/地区
的格式指定,例如,或
太平洋/奥克兰
。切勿使用3-4个字母的缩写,如
EST
IST
,因为它们不是真正的时区,也不是标准化的,甚至不是唯一的(!)

zdtEurope_伊斯坦布尔toString():2013-02-13T13:00:17.219+02:00[欧洲/伊斯坦布尔]

您可以应用其他时区

ZoneId zAmerica_Caracas = ZoneId.of( "America/Caracas" ) ;
ZonedDateTime zdtAmerica_Caracas = zdtEurope_Istanbul.withZoneSameInstant( zAmerica_Caracas ) ;
zdtAmerica_Caracas.toString():2013-02-13T06:30:17.219-04:30[美国/加拉加斯]

看这个

这三个物体,instant和zdtEurope_Istanbul和zdtAmerica_Caracas,都代表着非常相同的同时时刻,时间线上的相同点

您的历元计数代表UTC上午11点。伊斯坦布尔比UTC早两个小时,因此在同一时刻,那里的时间是上午11点、下午1点(13:00)后两个小时。委内瑞拉比UTC晚了四个半小时,因此那里一天中同一时刻的时间是早上6:30。这些都是有意义的,都是相同的时刻,但不同的挂钟时间

ISO 8601 请勿使用历元计数来交换或存储日期时间值。这很容易出错,不可能被人有意义地读取,而且不明确,因为不同的软件系统使用的时间段参考日期至少有几十个,粒度不同(整秒、毫秒、微秒、纳秒等)

在JVM之外传递日期时间值时,请使用文本表示的标准格式。在解析/生成字符串时,java.time类默认使用标准格式。您可以在这个答案的示例代码中看到这些格式


关于java.time 该框架内置于Java8及更高版本中