Skip to content

Commit 4effeeb

Browse files
committed
Fix #2743 - old date timezone precision in Chrome 67+
1 parent e7896e9 commit 4effeeb

File tree

2 files changed

+36
-4
lines changed

2 files changed

+36
-4
lines changed

src/lib/dates.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,16 @@ exports.dateTime2ms = function(s, calendar) {
138138
if(exports.isJSDate(s)) {
139139
// Convert to the UTC milliseconds that give the same
140140
// hours as this date has in the local timezone
141-
s = Number(s) - s.getTimezoneOffset() * ONEMIN;
141+
var tzOffset = s.getTimezoneOffset() * ONEMIN;
142+
var offsetTweak = (s.getUTCMinutes() - s.getMinutes()) * ONEMIN +
143+
(s.getUTCSeconds() - s.getSeconds()) * ONESEC +
144+
(s.getUTCMilliseconds() - s.getMilliseconds());
145+
146+
if(offsetTweak) {
147+
var comb = 3 * ONEMIN;
148+
tzOffset = tzOffset - comb / 2 + mod(offsetTweak - tzOffset + comb / 2, comb);
149+
}
150+
s = Number(s) - tzOffset;
142151
if(s >= MIN_MS && s <= MAX_MS) return s;
143152
return BADNUM;
144153
}

test/jasmine/tests/lib_date_test.js

+26-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@ describe('dates', function() {
2424
nowPlus29 = thisYear + 29,
2525
nowPlus29_2 = nowPlus29 % 100;
2626

27+
function tweakedTZOffset(d) {
28+
var tzOffset = d.getTimezoneOffset() * 60000;
29+
var offsetTweak = (d.getUTCMinutes() - d.getMinutes()) * 60000 +
30+
(d.getUTCSeconds() - d.getSeconds()) * 1000 +
31+
(d.getUTCMilliseconds() - d.getMilliseconds());
32+
33+
if(offsetTweak) {
34+
var comb = 3 * 60000;
35+
var tzOffset2 = tzOffset - comb / 2 + Lib.mod(offsetTweak - tzOffset + comb / 2, comb);
36+
// this tweak logic just copies what's in dateTime2ms to account for
37+
// Chrome's new handling of dates before there were timezones, see
38+
// https://github.com/plotly/plotly.js/issues/2743
39+
// This logic has been validated manually using:
40+
// Plotly.newPlot(gd,[{x:[new Date(1600,0,1),new Date(1600,0,1,0,1)],y:[1,2]}])
41+
// here just check that it's only happening for years before 1884,
42+
// and only adjusting the result less than a minute.
43+
expect(d.getFullYear()).toBeLessThan(1884);
44+
expect(Math.abs(tzOffset2 - tzOffset)).toBeLessThan(60000);
45+
return tzOffset2;
46+
}
47+
return tzOffset;
48+
}
49+
2750
describe('dateTime2ms', function() {
2851
it('should accept valid date strings', function() {
2952
var tzOffset;
@@ -62,9 +85,9 @@ describe('dates', function() {
6285
].forEach(function(v) {
6386
// just for sub-millisecond precision tests, use timezoneoffset
6487
// from the previous date object
65-
if(v[1].getTimezoneOffset) tzOffset = v[1].getTimezoneOffset();
88+
if(v[1].getTimezoneOffset) tzOffset = tweakedTZOffset(v[1]);
6689

67-
var expected = +v[1] - (tzOffset * 60000);
90+
var expected = +v[1] - tzOffset;
6891
expect(Lib.dateTime2ms(v[0])).toBe(expected, v[0]);
6992

7093
// ISO-8601: all the same stuff with t or T as the separator
@@ -108,7 +131,7 @@ describe('dates', function() {
108131
d1c,
109132
new Date(2015, 8, 7, 23, 34, 45, 567)
110133
].forEach(function(v) {
111-
expect(Lib.dateTime2ms(v)).toBe(+v - v.getTimezoneOffset() * 60000);
134+
expect(Lib.dateTime2ms(v)).toBe(+v - tweakedTZOffset(v), v.toString());
112135
});
113136
});
114137

0 commit comments

Comments
 (0)