我们知道java.util.Date的getTime方法返回自此Date对象表示的1970年1月1日格林尼治标准时间00:00:00以来的毫秒数。
我注意到以下一种奇怪的情况;
系统时区为:(UTC + 02:00)伊斯坦布尔
Date currentDate = new Date();
System.out.println(currentDate .getTime());
System.out.println(currentDate);
Java控制台输出:
1360753217219
2013年2月13日星期三13:00:17 VET
然后我的javascript插件正在使用如下所示的长对象;
Javascript:
console.log(new Date(1360753217219));
浏览器控制台输出:
日期{2013年2月13日星期三13:00:17 GMT + 0200(土耳其标准时间)}
没关系,但是!将我的本地时区更改为(UTC-04:30)加拉加斯后,情况和小时数以如下相同的毫秒数变化;
Javascript:
console.log(new Date(1360753217219));
浏览器控制台输出:
日期{2013年2月13日星期三06:30:17 GMT-0430(委内瑞拉标准时间)}
有人可以解释吗?那是js错误吗?或更重要的是,我应该如何在Java端处理此问题,以使JS端在不同时区获得相同的毫秒数的相同日期?
谢谢!
console.log((new Date(1360753217219)).toString())和console.log((new Date(1360753217219)).toUTCString())给您什么?
对不起,我只是没有看到问题。 加拉加斯的6:30在土耳其是13:00。 您到底想做什么?
相对于UTC的毫秒数是什么意思?
相同的"毫秒数"会导致在不同时区的不同时间。 我认为,下面的答案是正确的。
毫秒与时区无关。自格林尼治标准时间1970年1月1日起,时间以绝对时间计。因此,您的想法是得到毫秒,然后计算出给定时区的本地时间。如果您考虑一下,这是有道理的。无论您身在何处,自1970年以来经过的毫秒数都是相同的。
有点令人困惑,但不要为了适应时区而以毫秒为单位。每个日期库都具有将毫秒戳转换为时区特定本地时间的机制。
因此,如果您的特定问题是如何在服务器和客户端之间有效地交流日期(您所使用的语言并不重要),那么答案是,来回传递毫秒数并在任何一方计算出全局值是完全安全的您正在谈论的特定时间(如果这对您在这段时间所做的事情很重要)。
那是"自格林尼治标准时间1970年1月1日起-可能OP的混乱是由于未能理解纪元时间是在一个时区中而引起的。否则,经过的毫秒数将不会 无论您身在何处,都应保持一致。
是的...抱歉,我会改正我的答案。
不是错误,而是时区的工作方式。
如果您现在打电话给委内瑞拉的某人,问他现在几点了,他会告诉您
(根据您的示例)比土耳其时间早6.5小时(根据您的示例)。
正如您所提到的,您要处理的数字表示自1970年00:00:00 GMT以来在加拉加斯的毫秒数,即同一时间,时间是1969年12月31日19:30 GMT-0430
因此,无论几秒钟后,委内瑞拉的时间仍比格林尼治标准时间早4:30小时。
如果您使用相同的输入(毫秒),则无法在不同时区获得完全相同的日期,因为那完全是错误的。
如果要获得相同的结果,则可以将时区的差异(在这种情况下为6.5小时)添加到输出中。遵循Dredel博士的建议,您可能不应该弄乱毫秒。
更改毫秒实际上会更改时间(而不是时区)。 每个日期戳都有时区偏移量,作为总字符串的一部分。 在此基础上,很容易计算出需要从人类清晰的时间戳中减去/减去多少小时。 毫秒级的拧紧保证会给您带来麻烦,并且绝对是错误的解决方法。
@ Dr.Dredel感谢您的评论,我相应地更正了我的回复。
tl; dr
Instant.ofEpochMilli( 1_360_753_217_219L ) // UTC
2013-02-13T11:00:17.219Z
Instant.ofEpochMilli( 1_360_753_217_219L )
.atZone( ZoneId.of("Europe/Istanbul" ) ) // Same moment, two hours *ahead* of UTC.
2013-02-13T13:00:17.219+02:00[Europe/Istanbul]
Instant.ofEpochMilli( 1_360_753_217_219L )
.atZone( ZoneId.of("America/Caracas" ) ) // Same moment, four-and-a-half hours *behind* UTC.
2013-02-13T06:30:17.219-04:30[America/Caracas]
使用java.time
您正在使用与最早的Java版本捆绑在一起的麻烦的旧日期时间类。它们现在已被遗留,被java.time类(在任何平台上最好的日期时间库)所取代。
从您以UTC(1970-01-01T00:00:00Z)的1970年开始的纪元参考日期起的毫秒数开始。其他人指出,您可能没有把握一个纪元参考日期有一个时区,而在这个纪元中,这个时区是UTC(零时差)。所有其他偏移量都是以此为基准进行测量的,比UTC早或晚于UTC数小时零数分钟。
Instant类表示UTC时间轴上的时刻,其分辨率为纳秒(最多十进制的九(9)位数字)。
long input = 1_360_753_217_219L ;
Instant instant = Instant.ofEpochMilli( input ) ;
instant.toString(): 2013-02-13T11:00:17.219Z
如果您想通过特定区域的挂钟时间看到同一时刻,请设置一个时区。
时区是特定区域使用偏移量的过去,现在和将来的历史记录。
以continent/region格式指定正确的时区名称,例如America/Montreal,Africa/Casablanca或Pacific/Auckland。切勿使用3-4个字母的缩写,例如EST或IST,因为它们不是真实的时区,不是标准化的,甚至不是唯一的(!)。
ZoneId zEurope_Istanbul = ZoneId.of("Europe/Istanbul" ) ;
ZonedDateTime zdtEurope_Istanbul = instant.atZone( zEurope_Istanbul ) ;
zdtEurope_Istanbul.toString(): 2013-02-13T13:00:17.219+02:00[Europe/Istanbul]
您可以应用其他时区。
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[America/Caracas]
可以在IdeOne.com上实时查看此代码。
Instant&zdtEurope_Istanbul和zdtAmerica_Caracas这三个对象都表示同一时刻,即时间轴上的同一点。
您的从纪元开始算是UTC时间上午11点。伊斯坦布尔比UTC早两个小时,因此同一天的时间是上午11点,下午1点(13:00)之后的两个小时。委内瑞拉比世界协调时间晚四个半小时,因此同一天的时间是上午6:30。这些都是有意义的,所有相同的时刻,但不同的时钟时间。
ISO 8601
不要使用"从纪元开始计数"来交换或存储日期时间值。这很容易出错,难以被人类有意义地读取,并且模棱两可,因为各种软件系统使用了至少几十个纪元参考日期,并且具有不同的粒度(整秒,毫秒,微秒,纳秒等)。 )。
在JVM外部传递日期时间值时,请使用标准ISO 8601格式进行文本表示。解析/生成字符串时,java.time类默认使用标准格式。您可以在"答案"的示例代码中查看这些格式。
关于java.time
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧式旧式日期时间类,例如java.util.Date,Calendar和SimpleDateFormat。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参见Oracle教程。并在Stack Overflow中搜索许多示例和说明。规格为JSR 310。
在哪里获取java.time类?
Java SE 8,Java SE 9和更高版本
内置的
标准Java API的一部分,具有捆绑的实现。
Java 9添加了一些次要功能和修复。
Java SE 6和Java SE 7
java.time的许多功能在ThreeTen-Backport中都被反向移植到Java 6和7。
安卓系统
ThreeTenABP项目专门针对Android改编了ThreeTen-Backport(如上所述)。
请参阅如何使用ThreeTenABP…。
ThreeTen-Extra项目使用其他类扩展了java.time。该项目为将来可能在java.time中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval,YearWeek,YearQuarter等。