Skip to content

Commit 15cbde1

Browse files
authored
fix: use UTC time (#216)
1 parent 60ba8c2 commit 15cbde1

File tree

5 files changed

+59
-60
lines changed

5 files changed

+59
-60
lines changed

plugins/q/src/formatter/__tests__/timeFormat.spec.js

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,19 @@ import timeFormat, { QlikTimeToDate } from '../timeFormat';
88
* which means if you're specifying a date 2013-12-31 59:59:59 and the last millisecond,
99
* you *might* end up in 2014.
1010
*/
11+
const QT = QlikTimeToDate(0).getTime();
1112
function DateToQlikTime(value) {
12-
let offset = QlikTimeToDate(0);
13-
14-
const off2 = ((offset.getTimezoneOffset() * 60 * 1000) - (value.getTimezoneOffset() * 60 * 1000)) + (offset.getTimezoneOffset() * 60 * 1000);
15-
16-
offset = offset.setTime(offset.getTime() + (value.getTimezoneOffset() * 60 * 1000));
17-
18-
return (
19-
((value.getTime() - offset) + off2 + 0.5) / (60 * 60 * 24)
20-
) / 1000;
13+
return (value.getTime() - QT) / (60 * 60 * 24) / 1000;
2114
}
2215

2316
describe('qlik timeFormat', () => {
2417
let n;
2518

19+
it('should create valid qlik date -> JS Date', () => {
20+
let d = QlikTimeToDate(0);
21+
expect(d.toISOString()).to.equal('1899-12-30T00:00:00.000Z');
22+
});
23+
2624
describe('Basic', () => {
2725
it('should format dates correctly according to constructor pattern', () => {
2826
const formatter = timeFormat('MMMM DD, YYYY');
@@ -89,7 +87,7 @@ describe('qlik timeFormat', () => {
8987
describe('Years', () => {
9088
it('should format year correctly', () => {
9189
n = timeFormat();
92-
let d = DateToQlikTime(new Date(2014, 3, 24, 13, 55, 40, 100)); // thursday 24th april 2014 @ 13:55:40:100
90+
let d = DateToQlikTime(new Date(Date.UTC(2014, 3, 24, 13, 55, 40, 100))); // thursday 24th april 2014 @ 13:55:40:100
9391

9492
expect(n.format('Y', d)).to.equal('14');
9593
expect(n.format('y', d)).to.equal('14');
@@ -102,7 +100,7 @@ describe('qlik timeFormat', () => {
102100
expect(n.format('YYYYY', d)).to.equal('02014');
103101
expect(n.format('YYYYYY YY', d)).to.equal('002014 14');
104102

105-
d = DateToQlikTime(new Date(123401, 11, 1, 13, 55, 40, 100));
103+
d = DateToQlikTime(new Date(Date.UTC(123401, 11, 1, 13, 55, 40, 100)));
106104
expect(n.format('Y', d)).to.equal('1');
107105
expect(n.format('YY', d)).to.equal('01');
108106
expect(n.format('YYY', d)).to.equal('401');
@@ -125,18 +123,18 @@ describe('qlik timeFormat', () => {
125123
_11;
126124
beforeEach(() => {
127125
n = timeFormat();
128-
_0 = DateToQlikTime(new Date(2014, 0, 1));
129-
_1 = DateToQlikTime(new Date(2014, 1, 1));
130-
_2 = DateToQlikTime(new Date(2014, 2, 1));
131-
_3 = DateToQlikTime(new Date(2014, 3, 1));
132-
_4 = DateToQlikTime(new Date(2014, 4, 1));
133-
_5 = DateToQlikTime(new Date(2014, 5, 1));
134-
_6 = DateToQlikTime(new Date(2014, 6, 1));
135-
_7 = DateToQlikTime(new Date(2014, 7, 1));
136-
_8 = DateToQlikTime(new Date(2014, 8, 1));
137-
_9 = DateToQlikTime(new Date(2014, 9, 1));
138-
_10 = DateToQlikTime(new Date(2014, 10, 1));
139-
_11 = DateToQlikTime(new Date(2014, 11, 1));
126+
_0 = DateToQlikTime(new Date(Date.UTC(2014, 0, 1)));
127+
_1 = DateToQlikTime(new Date(Date.UTC(2014, 1, 1)));
128+
_2 = DateToQlikTime(new Date(Date.UTC(2014, 2, 1)));
129+
_3 = DateToQlikTime(new Date(Date.UTC(2014, 3, 1)));
130+
_4 = DateToQlikTime(new Date(Date.UTC(2014, 4, 1)));
131+
_5 = DateToQlikTime(new Date(Date.UTC(2014, 5, 1)));
132+
_6 = DateToQlikTime(new Date(Date.UTC(2014, 6, 1)));
133+
_7 = DateToQlikTime(new Date(Date.UTC(2014, 7, 1)));
134+
_8 = DateToQlikTime(new Date(Date.UTC(2014, 8, 1)));
135+
_9 = DateToQlikTime(new Date(Date.UTC(2014, 9, 1)));
136+
_10 = DateToQlikTime(new Date(Date.UTC(2014, 10, 1)));
137+
_11 = DateToQlikTime(new Date(Date.UTC(2014, 11, 1)));
140138
});
141139

142140
it('as number', () => {
@@ -214,13 +212,13 @@ describe('qlik timeFormat', () => {
214212
sun;
215213
beforeEach(() => {
216214
n = timeFormat(null);
217-
mon = DateToQlikTime(new Date(2014, 0, 6));
218-
tue = DateToQlikTime(new Date(2014, 0, 7));
219-
wed = DateToQlikTime(new Date(2014, 0, 8));
220-
thu = DateToQlikTime(new Date(2014, 0, 9));
221-
fri = DateToQlikTime(new Date(2014, 0, 10));
222-
sat = DateToQlikTime(new Date(2014, 0, 11));
223-
sun = DateToQlikTime(new Date(2014, 0, 12));
215+
mon = DateToQlikTime(new Date(Date.UTC(2014, 0, 6)));
216+
tue = DateToQlikTime(new Date(Date.UTC(2014, 0, 7)));
217+
wed = DateToQlikTime(new Date(Date.UTC(2014, 0, 8)));
218+
thu = DateToQlikTime(new Date(Date.UTC(2014, 0, 9)));
219+
fri = DateToQlikTime(new Date(Date.UTC(2014, 0, 10)));
220+
sat = DateToQlikTime(new Date(Date.UTC(2014, 0, 11)));
221+
sun = DateToQlikTime(new Date(Date.UTC(2014, 0, 12)));
224222
});
225223

226224
it('as number', () => {
@@ -318,9 +316,9 @@ describe('qlik timeFormat', () => {
318316
_31;
319317
beforeEach(() => {
320318
n = timeFormat(null);
321-
_1 = DateToQlikTime(new Date(2014, 0, 1));
322-
_15 = DateToQlikTime(new Date(2014, 0, 15));
323-
_31 = DateToQlikTime(new Date(2014, 0, 31));
319+
_1 = DateToQlikTime(new Date(Date.UTC(2014, 0, 1)));
320+
_15 = DateToQlikTime(new Date(Date.UTC(2014, 0, 15)));
321+
_31 = DateToQlikTime(new Date(Date.UTC(2014, 0, 31)));
324322
});
325323

326324
it('as number', () => {
@@ -353,7 +351,7 @@ describe('qlik timeFormat', () => {
353351
describe('Combinations', () => {
354352
it('should support combinations of year, month, weekday and day', () => {
355353
n = timeFormat(null);
356-
const d = DateToQlikTime(new Date(2014, 3, 24, 13, 55, 40, 100)); // thursday 24th april 2014 @ 13:55:40:100
354+
const d = DateToQlikTime(new Date(Date.UTC(2014, 3, 24, 13, 55, 40, 100))); // thursday 24th april 2014 @ 13:55:40:100
357355

358356
expect(n.format('YYYY-MM-DD', d)).to.equal('2014-04-24');
359357
expect(n.format('DD/MM -YY', d)).to.equal('24/04 -14');
@@ -448,19 +446,19 @@ describe('qlik timeFormat', () => {
448446

449447
describe('Fractions', () => {
450448
it(' ', () => {
451-
const d = DateToQlikTime(new Date(2014, 0, 1, 0, 0, 0, 456));
449+
const d = DateToQlikTime(new Date(Date.UTC(2014, 0, 1, 0, 0, 0, 452)));
452450
expect(n.format('f F', d)).to.equal('4 4'); // tenths of a second
453451
expect(n.format('ff', d)).to.equal('45'); // hundreths of a second
454-
expect(n.format('fff FFF', d)).to.equal('456 456'); // tousandths of a second
455-
expect(n.format('ffff', d)).to.equal('4560'); // ten thousandths of a second
456-
expect(n.format('fffff', d)).to.equal('45600'); // hundred thousandths of a second
457-
expect(n.format('ffffff', d)).to.equal('456000'); // millionths of a second
452+
expect(n.format('fff FFF', d)).to.equal('452 452'); // tousandths of a second
453+
expect(n.format('ffff', d)).to.equal('4520'); // ten thousandths of a second
454+
expect(n.format('fffff', d)).to.equal('45200'); // hundred thousandths of a second
455+
expect(n.format('ffffff', d)).to.equal('452000'); // millionths of a second
458456
});
459457
});
460458

461459
it('should support combinations of hours, minutes, seconds and fractions', () => {
462460
const d = 41753.58033550347;
463-
// let d = DateToQlikTime(new Date(2014, 3, 24, 13, 55, 40, 987));
461+
// let d = DateToQlikTime(new Date(Date.UTC(2014, 3, 24, 13, 55, 40, 987));
464462

465463
expect(n.format('h:m:s', midnight)).to.equal('0:0:0');
466464
expect(n.format('hh:mm:ss', midnight)).to.equal('00:00:00');
@@ -471,7 +469,7 @@ describe('qlik timeFormat', () => {
471469
expect(n.format('h:m:s tt', noon59)).to.equal('12:59:0 pm');
472470
expect(n.format('h:m:s[.fff]][', noon59)).to.equal('12:59:0');
473471

474-
// expect( n.format( new Date( 2014, 0, 1, 13, 55, 30, 123 ), 'h:m:s[.ffff]' ) ).to.equal( '13:55.30.1230' ); // TODO?
472+
// expect( n.format( new Date(Date.UTC( 2014, 0, 1, 13, 55, 30, 123 ), 'h:m:s[.ffff]' ) ).to.equal( '13:55.30.1230' ); // TODO?
475473

476474
expect(n.format('YYYY-MM-DD hh:mm:ss.ffff', d)).to.equal('2014-04-24 13:55:40.9870');
477475
expect(n.format('DD/MM -YY h:m:s.fff TT', d)).to.equal('24/04 -14 1:55:40.987 PM');

plugins/q/src/formatter/parts/qs-date-formatter.js

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ function pad(s, n) {
1313
}
1414

1515
function parseDate(d, twelveFormat) {
16-
let h = d.getHours();
17-
let day = d.getDay() - 1;
16+
let h = d.getUTCHours();
17+
let day = d.getUTCDay() - 1;
1818
if (twelveFormat) {
1919
h %= 12;
2020
if (!h) { // h == 0 -> 12
@@ -27,15 +27,15 @@ function parseDate(d, twelveFormat) {
2727
}
2828

2929
return {
30-
year: d.getFullYear(),
31-
month: d.getMonth(),
30+
year: d.getUTCFullYear(),
31+
month: d.getUTCMonth(),
3232
day,
33-
date: d.getDate(),
33+
date: d.getUTCDate(),
3434
h,
35-
m: d.getMinutes(),
36-
s: d.getSeconds(),
37-
f: d.getMilliseconds(),
38-
t: d.getHours() >= 12 ? 'pm' : 'am'
35+
m: d.getUTCMinutes(),
36+
s: d.getUTCSeconds(),
37+
f: d.getUTCMilliseconds(),
38+
t: d.getUTCHours() >= 12 ? 'pm' : 'am'
3939
};
4040
}
4141

@@ -76,7 +76,7 @@ function parseInterval(days, pattern) {
7676
date;
7777

7878
if (/w+|t+/gi.test(pattern)) {
79-
date = new Date(1899, 11, 30 + Math.floor(days), 0, 0, 24 * 60 * 60 * (days - Math.floor(days)));
79+
date = new Date(Date.UTC(1899, 11, 30 + Math.floor(days), 0, 0, 24 * 60 * 60 * (days - Math.floor(days))));
8080
if (isNaN(date.getTime())) {
8181
date = null;
8282
}
@@ -100,7 +100,7 @@ function parseInterval(days, pattern) {
100100

101101
let someT = '';
102102
if (date) {
103-
someT = date.getHours() >= 12 ? 'pm' : 'am';
103+
someT = date.getUTCHours() >= 12 ? 'pm' : 'am';
104104
}
105105

106106
return {

plugins/q/src/formatter/timeFormat.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import dateFormatFactory from './parts/qs-date-formatter';
22
import { TYPES } from './constants';
33

44
export function QlikTimeToDate(value) {
5-
return new Date(1899, 11, 30 + Math.floor(value), 0, 0, 0, 1000 * 24 * 60 * 60 * (value - Math.floor(value)));
5+
return new Date(Date.UTC(1899, 11, 30 + Math.floor(value), 0, 0, 0, 1000 * 24 * 60 * 60 * (value - Math.floor(value))));
66
}
77

88
export default function formatter(pattern, qtype = 'TS', localeInfo = null) {

plugins/q/src/scales/qTime/__tests__/tick-generator.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,15 @@ describe('qTime - Tick generator', () => {
9090
expect(ticks[0].label).to.equal('00:00');
9191
});
9292

93-
it.skip('should generate ticks even when no distance argument is passed', () => {
93+
it('should generate ticks even when no distance argument is passed', () => {
9494
tickFn = tickGenerator(scale, settings);
9595

9696
const ticks = tickFn.createTicks();
9797

9898
expect(ticks).to.be.of.length(9);
9999
});
100100

101-
it.skip('should generate appropriate amount of ticks based on distance', () => {
101+
it('should generate appropriate amount of ticks based on distance', () => {
102102
tickFn = tickGenerator(scale, settings);
103103

104104
let ticks = tickFn.createTicks(120);
@@ -109,7 +109,7 @@ describe('qTime - Tick generator', () => {
109109
expect(ticks).to.be.of.length(9);
110110
});
111111

112-
it.skip('should output ticks in picasso format', () => {
112+
it('should output ticks in picasso format', () => {
113113
tickFn = tickGenerator(scale, settings);
114114

115115
const ticks = tickFn.createTicks(120);

plugins/q/src/scales/qTime/tick-generator.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { scaleTime as d3ScaleTime } from 'd3-scale';
1+
import { scaleUtc as d3ScaleTime } from 'd3-scale';
22
import { createFromMetaInfo } from '../../formatter';
33
import { QlikTimeToDate } from '../../formatter/timeFormat';
44

5-
const UNIX_DATE_COMP_DAYS = 25569;
5+
// const UNIX_DATE_COMP_DAYS = 25569;
66
const HOUR_PATTERN = 'hh:mm';
77
const MINUTE_PATTERN = 'hh:mm:ss';
88

9+
const QT = QlikTimeToDate(0).getTime();
10+
911
function DateToQlikTimestamp(date) {
10-
const offset = (date.getTimezoneOffset() / 60 / 24) - UNIX_DATE_COMP_DAYS;
11-
return ((date.getTime() + 0.5) / 1000 / 86400) - offset;
12+
return (date.getTime() - QT) / (60 * 60 * 24) / 1000;
1213
}
1314

1415
function getFormatter(ticks) {

0 commit comments

Comments
 (0)