Javascript Date和java.util.Date构造函数参数



是的,关于Java和Javascript中Date的另一个问题。

Java和浏览器(Chrome)的时区均为GMT+4(莫斯科)。

<script language="javascript">
  var d = new Date(170798400000);
  document.write(d);
</script>

给出:孙1975年6月1日00:00:00 GMT+0400(俄罗斯标准时间)

public class Test {
    public static void main(String[] args) {
        java.util.Date d = new java.util.Date(170798400000L); // the same epoch value!
        System.out.println(d);
    }
}

给出:5月31日星期六23:00:00 MSK 1975

如果我将历元值更改为2011-2012年(在俄罗斯取消夏令时后),输出是可以的。时区更新工具运行正常。

这是一个bug还是已记录的功能?除了格式化和重新解析(例如YYYY-MM-dd HH:MM:SS)之外,还有什么方法可以处理这个问题吗

来自javadoc:

日期(长日期)

分配Date对象并对其进行初始化,以表示自1970年1月1日00:00:00 GMT的标准基准时间以来指定的毫秒数。

来自javascript引用:

新日期(毫秒)

毫秒-表示自1970年1月1日00:00:00 UTC(Unix Epoch)以来的毫秒数的整数值。

这是一个bug还是有文档记录的功能?

这不是Javascript的错误。至少,我看不出我可以这么说。

浏览器的Javascript引擎正在返回转换为"GMT+4"的时间。显然,你想要的是MSK,它与GMT+4不同(正如你的评论中所指出的)。Javascript不了解MSK并不算是一个bug,而是缺少一个功能。也许js对时区没有那么详细的了解是"错误的",但它不是一个bug。

除了格式化和重新解析(例如YYYY-MM-dd HH:MM:SS)之外,还有什么方法可以处理这个问题吗?

追踪时区的所有任意细节需要做很多工作。据我所知,没有这样的代码库可以为javascript提供所有的工作。因此,我相信,是的,如果你想使用真正的MSK,你必须自己手动编码转换。

时间的字符串表示(如"Sun Jun 01 1975 00:00:00 GMT+0400")用于人类。时间值(自1970年1月1日UTC以来的毫秒)用于存储和计算。

那里没有bug。在JavaScript中,根据规范,字符串表示的内容取决于实现。在Java中,根据文档,夏令时可能会被反映出来。

来自JavaScript规范:

15.9.5.2 Date.prototype.toString ( )

此函数返回一个字符串值。String的内容依赖于实现->,但旨在以方便的、可读的形式表示当前时区中的日期

来自Java文档:

java.util.Date, public String toString()
Converts this Date object to a String of the form: dow mon dd hh:mm:ss zzz yyyy
where:
...
zzz is the time zone (and may reflect daylight saving time).`

tl;dr

Instant.ofEpochMilli( 170_798_400_000L )

1975-05-31T20:00:00Z

…和…

Instant.ofEpochMilli( 170_798_400_000L )
       .atZone( ZoneId.of( "Europe/Moscow" ) )

1975-05-31T23:00+03:00[欧洲/莫斯科]

请参阅实时代码。

使用java.time

现代方法使用java 8及更高版本中的java.time类。

您正在使用Java中麻烦的旧日期时间类,这些类现在是遗留的。在这些类的许多问题中,Date::toString方法在生成字符串时应用当前默认时区,这是出于善意但令人困惑的特性。内部值实际上总是以UTC为单位,但toString会产生一种错觉,即Date有时区,而实际上它没有。这就解释了你的MSK之谜。

[更令人困惑的是,实际上Date中有一个时区,但与本次讨论无关。那些旧的Date/Calendar类一团糟。幸运的是,Java现在拥有任何平台上最好的类内日期-时间框架:Java.time。]

显然,您的输入表示自Unix纪元1970-01-01T00:00:00Z以来的毫秒数。

Instant类表示以UTC为单位的时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数)。这个类可以直接解析您的输入数字。

Instant instant = Instant.ofEpochMilli( 170_798_400_000L ) ;

instant.toString():1975-05-31T20:00:00Z

如果你想通过特定地区的挂钟时间来观察同一时刻,可以应用时区。应用ZoneId以获得ZonedDateTime对象。

ZoneId z = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

1975-05-31T23:00+03:00[欧洲/莫斯科]

JavaScript库不正确

您对JavaScript库的调用结果不正确,偏移量为+04:00。根据维基百科,莫斯科时间从1930年到1981年提前了三个小时,+03:00。java.time框架在1975年全年产生+03:00的正确结果。请参阅俄罗斯时间了解更多信息。注意:我不是俄罗斯/苏联时期的专家。


关于java.time

java.time框架是在java 8及更高版本中构建的。这些类取代了诸如java.util.DateCalendar、&SimpleDateFormat

JodaTime项目现在处于维护模式,建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

从哪里获得java.time类?

  • Java SE 8Java SE 9及更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • ThreeTenABP项目专门为安卓系统改编了ThreeTen Backport(如上所述)
    • 请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

相关内容

  • 没有找到相关文章

最新更新