momentjs toDate - 不同 clients/browsers 上的不同输出

momentjs toDate - different output on different clients/browsers

我使用 momentjs 解析日期字符串并将其转换为原生 JavaScript 日期:

let dateString = '1980-04-06';
console.log(moment().utcOffset());
console.log(moment(dateString, 'YYYY-MM-DD').toDate());
<script src="https://cdn.jsdelivr.net/npm/moment@2.22.2/moment.min.js"></script>

客户端 1(Firefox 62) 上的输出是

120
Date 1980 - 04 - 05 T23: 00: 00.000 Z

客户端 2(Firefox 52 ESR) 上的输出是

120
Date 1980 - 04 - 05 T22: 00: 00.000 Z

有人可以解释一下,为什么 utcOffset 相同(new Date().getTimezoneOffset() 在两个客户端上也打印 -120),但日期(小时)不同?

您正在检查 当前 UTC 偏移量,而不是 1980 时刻实例的偏移量。我的猜测是,如果你在 that 上使用 moment(dateString, 'YYYY-MM-DD') 并调用 utcOffset,你会在不同的浏览器上获得不同的偏移量。

我敢打赌,您所在区域的规则自 1980 年以来发生了变化(例如,DST 的时间可能发生了变化,或者 DST 已被添加或取消,或者标准偏移量可能甚至发生了变化) .浏览器在正确获取历史区域数据的程度上各不相同,这会导致错误解释日期字符串。我怀疑 Firefox 为您的区域修复了他们的历史区域数据库,导致在新版本的浏览器中出现不同的行为。

您显示的偏移量是针对当前 日期和时间的,而不是针对提供的日期。如果您将中间行更改为记录 moment(dateString, 'YYYY-MM-DD').utcOffset(),您应该会看到在较旧的 Firefox 52 中的结果是 60 而不是 120.

解释这种差异的因素是:

  • 您所在时区的夏令时规则在 1980 年与今天不同。假设维也纳(根据您的用户个人资料),1980 年 DST 的开始时间是 4 月 6 日 00:00 (reference here) which is the first Sunday in April. The current (2018) rule for Vienna is the last Sunday in March, which would be March 25th 2018 (reference here)。

  • ECMAScript 5.1 (section 15.9.1.8) and earlier required browsers to always assume the current DST rule was in effect for all time - even if this was not actually what happened. This was corrected in ECMAScript 6 / 2015 (section 20.3.1.8) .

  • ECMAScript 2015 从版本 54 开始在 Firefox 中实现。由于您正在测试版本 52,因此您看到的是旧行为。

  • 由于这个特定的 DST 更改恰好在午夜敲响,并且它是一个 spring-forward 转换,因此,1980-04-06T00:00 无效。该时区当天的第一时刻是 1980-04-06T01:00。当您传递一个仅限日期的值时,Moment 会为您解决这个问题。在当前的浏览器中(62,不是 52),如果你现在调用 .format(),你应该看到 1980-04-06T01:00:00+02:00。请注意,该时间已经采用 DST,具有 UTC+02:00 偏移量。转换为 UTC 是 1980-04-05T23:00:00Z,因此与您的示例中看到的正确数据对齐。

长话短说,使用最新浏览器的原因有很多。这是其中之一。