最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - weird seconds offset in js date object in chrome - Stack Overflow

programmeradmin3浏览0评论

When looking at the valueOf value of a date object at the beggining of a year i expected to always receive zero seconds. The following code shows that until 1917 there was an offset of 54 seconds or 40 seconds in chrome. in IE i receive 0 seconds for all years.

Is there a reason for this? it seems to only happen in the last chrome version

   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]})

When looking at the valueOf value of a date object at the beggining of a year i expected to always receive zero seconds. The following code shows that until 1917 there was an offset of 54 seconds or 40 seconds in chrome. in IE i receive 0 seconds for all years.

Is there a reason for this? it seems to only happen in the last chrome version

   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]})
Share Improve this question asked Jun 14, 2018 at 12:07 DanielDaniel 2,3813 gold badges27 silver badges35 bronze badges 10
  • So, in other words: new Date(1915, 0, 1, 0, 0, 0).toUTCString() results in "Thu, 31 Dec 1914 22:36:00 GMT" (Chrome 67.0.3396.87). Thats really strange, and I think it's a bug. Did You report that? – Krzysztof Grzybek Commented Jun 14, 2018 at 15:30
  • In Chrome 67.0.3396.87 on Windows new Date(1915, 0, 1, 0, 0, 0).toUTCString() returns "Fri, 01 Jan 1915 00:00:00 GMT" – Eliott Robson Commented Jun 20, 2018 at 7:24
  • 1 @KrzysztofGrzybek as a sidenote: new Date(1915, 0, 1, 0, 0, 0) gives output "Fri Jan 01 1915 00:00:00 GMT+0124" and difference is indeed 1h 24min. Also getTimezoneOffset returns -84 (1h 24min) – barbsan Commented Jun 20, 2018 at 10:00
  • 1 This is an annoying bug introduced with Chrome 67. It seems it want to use some sort of interpolated time zone from historical data (you can see historical time zones down to year 1800 in timeanddate.com), and this is adding these minute shifts to dates. – Fabrício Murta Commented Jun 21, 2018 at 4:46
  • 2 Everyone: This is not a bug. This happens in almost literally every single timezone, and the values have been present in the tz database for almost three decades. If your code can't handle values before ~1883–1914, then I guarantee you your code is also incorrect around daylight saving transitions and changes to the timezone data, today, for real, non-historical values. – Josh Lee Commented Jun 24, 2018 at 19:07
 |  Show 5 more comments

2 Answers 2

Reset to default 17 +100

This is Not a BUG..

As @Krzysztof pointed out Chrome has implemented a new spec for timezone offset calculation following the merge of Make LocalTZA take 't' and 'isUTC' and drop DSTA(t) to Ecma 262. So now the time-zone conversion does not work by just backward interval of seconds, it is calculated as what local time was being observed in a specific region.

Explanation:

I am from a wonderful little country called Bangladesh of South-Asia which follows BST(Bangladesh Standard Time +0600 GMT), which was not always exactly 6 hours ahead of GMT. As JavaScript date takes in local time when I print the start time of this year in GMT I get:

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

In 2009 one hour day-light saving was observed in Bangladesh from 19 June to 31 December. So if I print the first day of December 2009 I get:

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

You can see the day-light saving is now reflected in the date now, which is not visible in my nodeJS console. There was also changes in local time in 1941-1942 as shown below and can be seen on timeanddate.com:

All of the changes are reflected in Chrome now:

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"

So now if I pick any date before 1941 keeping in mind my local time is 6 hours ahead I see an offset of 6 minutes 40 seconds. It will vary depending on the time-zone for the back dates due to the recent update of Chrome, or specifically saying the update of ECMAScript(JavaScript).

This may not be 100% the solution of the problem, but one can get the "jitter" introduced by chrome by casting it to UTC and back, then compensate with a new 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;
        }

This "jitter" pretty much depends on the time zone. For Brazil I'm getting a 28 seconds noise (so it gets back to like, 12:00:00 AM > 23:59:32 PM the previous day.

For Brazil the issue happens down to 1913. This coincides with the time we got our daylight saving times and time zone to -3:00 from -3:06, according to the time changes over years at https://www.timeanddate.com/time/zone/brazil/sao-paulo.

With the above code you can explore the broken dates with this loop:

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());
  }
 }
}
发布评论

评论列表(0)

  1. 暂无评论