【问题标题】:weird seconds offset in js date object in chromechrome中js日期对象中奇怪的秒偏移
【发布时间】:2018-06-14 12:07:01
【问题描述】:

在年初查看日期对象的 valueOf 值时,我希望总是收到零秒。 以下代码显示,直到 1917 年,chrome 中的偏移量为 54 秒或 40 秒。在 IE 中,我所有年份都收到 0 秒。

这是有原因的吗?它似乎只发生在最后一个 chrome 版本中

   for(var i=0; i<2020;i++)
       if(!new Date(i,0,1).valueOf().toString().match("00000$"))
             console.log({
                    y:i,
                    s: new Date(i,0,1).valueOf().toString().match(/(\d{2})\d{3}$/)[1]})

【问题讨论】:

  • 因此,换句话说:new Date(1915, 0, 1, 0, 0, 0).toUTCString() 导致 "Thu, 31 Dec 1914 22:36:00 GMT" (Chrome 67.0.3396.87)。这真的很奇怪,我认为这是一个错误。你举报了吗?
  • 在 Windows 上的 Chrome 67.0.3396.87 中 new Date(1915, 0, 1, 0, 0, 0).toUTCString() 返回 "Fri, 01 Jan 1915 00:00:00 GMT"
  • @KrzysztofGrzybek 作为旁注:new Date(1915, 0, 1, 0, 0, 0) 给出输出“Fri Jan 01 1915 00:00:00 GMT+0124”,差异确实是 1 小时 24 分钟。同样getTimezoneOffset 返回 -84(1 小时 24 分钟)
  • 这是 Chrome 67 引入的一个烦人的错误。它似乎想使用从历史数据中插入的某种插值时区(您可以在 timeanddate.com 中查看到 1800 年的历史时区),这就是将这些分钟班次添加到日期中。
  • 大家:这不是错误。这几乎发生在每个时区,并且这些值已经在 tz 数据库中存在了近三年。如果您的代码无法处理 ~1883–1914 之前的值,那么我向您保证,您的代码在夏令时转换和时区数据更改方面也不正确,今天,对于真实的非历史值.

标签: javascript google-chrome datetime


【解决方案1】:

不是BUG..

正如@Krzysztof 指出的那样,Chrome 在将Make LocalTZA take 't' and 'isUTC' and drop DSTA(t) 合并到 Ecma 262 之后具有implemented a new spec for timezone offset calculation。所以现在时区转换仅按向后的秒间隔不起作用,它被计算为 what local正在观察特定区域的时间

说明:

我来自南亚的一个名为孟加拉国的美妙小国,该国遵循BST(孟加拉国标准时间+0600 GMT),即并不总是比格林威治标准时间提前 6 小时。当我在 GMT 打印今年的开始时间时,JavaScript date 采用当地时间,我得到:

new Date(2018, 0, 1).toUTCString()
// "Sun, 31 Dec 2017 18:00:00 GMT"

2009 年,one hour day-light saving 于 6 月 19 日至 12 月 31 日在孟加拉国被观测到。因此,如果我打印 2009 年 12 月的第一天,我会得到:

new Date(2009, 11, 1).toUTCString()
// "Mon, 30 Nov 2009 17:00:00 GMT"

您可以看到夏令时现在反映在日期中,这在我的nodeJS 控制台中不可见。 1941-1942年的当地时间也有变化,如下图,可以在timeanddate.com看到:

所有更改现在都反映在 Chrome 中:

new Date(1941, 6, 1).toUTCString()
// "Mon, 30 Jun 1941 18:06:40 GMT"

new Date(1941, 11, 1).toUTCString()
// "Sun, 30 Nov 1941 17:30:00 GMT"

new Date(1942, 7, 1).toUTCString()
// "Fri, 31 Jul 1942 18:30:00 GMT"

new Date(1942, 11, 1).toUTCString()
// "Mon, 30 Nov 1942 17:30:00 GMT"

所以现在,如果我选择 1941 年之前的任何日期,请记住我的当地时间提前 6 小时,我会看到 6 分 40 秒的偏移量。由于最近 Chrome 的更新,或者特别是 ECMAScript(JavaScript) 的更新,它会根据回溯日期的时区而有所不同。

【讨论】:

  • 你的意思是 chrome 调查了世界各地的历史 TZ 变化。是不是很夸张? chrome 在耶路撒冷 (+02:00) 的变化可以追溯到公元 0018 年。
  • 我不同意这也不是错误。这会带来更多的麻烦。应该 - 至少 - 有一种方法可以选择退出这种只在 chrome 上存在的细致的时区考虑。这只是回到浏览器大战。
  • @FabrícioMurta 这不是错误,而是 JavaScript 的更新,迟早所有浏览器都会实现它。解决它的最简单方法是使用Date.UTC。而不是new Date(1942, 11, 1) 使用new Date(Date.UTC(1942, 11, 1))
【解决方案2】:

这可能不是 100% 的问题解决方案,但可以通过将 chrome 转换为 UTC 并返回来获得由 chrome 引入的“抖动”,然后用新的new Date(oldDate.getTime() + jitter) 进行补偿。

        // Compensates for google chrome 67+ issue with very old dates.
        // We should skip this test if any other browser.
        $getJitter: function (d) {
            var utcDate = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), d.getUTCHours(), d.getUTCMinutes(), d.getUTCMilliseconds())),
                jitter = 0;

            // As we're setting UTC date, the non-UTC year could be
            // shifted one ahead or behind, so set the utc full
            // year to ensure compliance.
            utcDate.setUTCFullYear(d.getUTCFullYear());

            if (d.getFullYear() != utcDate.getFullYear() ||
                d.getMonth() != utcDate.getMonth() ||
                d.getDate() != utcDate.getDate() ||
                d.getHours() != utcDate.getHours() ||
                d.getMinutes() != utcDate.getMinutes() ||
                d.getMilliseconds() != utcDate.getMilliseconds()) {

                // infers the "jitter" introduced during the conversion to compensate in the
                // actual value of ticks
                jitter = d.getTime() - utcDate.getTime()
            }

            return jitter;
        }

这种“抖动”很大程度上取决于时区。对于巴西,我收到了 28 秒的噪音(所以它会恢复到前一天的 12:00:00 AM > 23:59:32 PM。

对于巴西,问题发生在 1913 年。这与我们将夏令时和时区从 -3:06 变为 -3:00 的时间一致,根据https://www.timeanddate.com/time/zone/brazil/sao-paulo 多年来的时间变化。

使用上面的代码,您可以使用此循环探索损坏的日期:

for (var i=1900; i < 2020; i++) {
 for (var j=0; j < 12; j++) {
  var dt = new Date(i, j, 1);
  var jitter = System.DateTime.$getJitter(dt);
  if (jitter != 0) {
   console.log("broken: " + i + ", " + j + ", jitter: " + (jitter/1000) + "s: " + dt.toString());
  }
 }
}

【讨论】:

  • 我只是想补充一点,这不是 chrome 中的错误,这种行为是最近在 ecma 规范中定义的,所以它可能很快也会出现在其他浏览器中。 chromium-review.googlesource.com/c/v8/v8/+/572148
  • 我仍然相信那里有一个错误,好像我转换为 UTC 然后回到时间,我得到一个不同的值。它至少应该是一致的。
  • 您不是“转换为 UTC 然后回到时间”。您丢弃了 UTC 偏移量,丢弃了 seconds 字段,然后抱怨值不同。将一个日期的 UTC 偏移量应用到另一个日期是完全错误的。
  • 我正在获取时间是否有秒数抖动,以便我可以放弃它,这是为了克服烦人的问题。我故意删除数据以查看它是否更改了不需要的字段,以便我可以识别和解决问题,只有当它发生时......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-08
  • 1970-01-01
  • 1970-01-01
  • 2014-11-03
  • 2017-03-18
相关资源
最近更新 更多