From fba8652f6cca949c8986e51be75e62d4e1c6f3fc Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 26 Nov 2024 13:31:45 -0800 Subject: [PATCH 1/5] init --- .idea/prettier.xml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .idea/prettier.xml diff --git a/.idea/prettier.xml b/.idea/prettier.xml new file mode 100644 index 0000000..b0c1c68 --- /dev/null +++ b/.idea/prettier.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file From aa57c9efe58e4f39af50c97e9eab6bc5a4702791 Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Tue, 26 Nov 2024 14:23:16 -0800 Subject: [PATCH 2/5] switch to internationalized_date --- package-lock.json | 34 ++++++-- package.json | 2 +- src/date-parser/date-parser.ts | 38 +++----- src/floor-shift-ceil/floor-shift-ceil.spec.ts | 8 +- src/floor-shift-ceil/floor-shift-ceil.ts | 86 ++++++++----------- src/timezone/timezone.ts | 14 +-- tsconfig.json | 2 +- 7 files changed, 90 insertions(+), 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8aaf76a..40d4b53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -555,6 +555,14 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@internationalized/date": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.6.0.tgz", + "integrity": "sha512-+z6ti+CcJnRlLHok/emGEsWQhe7kfSmEW+/6qCzvKY67YPh7YOBfvc7+/+NXq+zJlbArg30tYpqLjNgcAYv2YQ==", + "requires": { + "@swc/helpers": "^0.5.0" + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1156,6 +1164,21 @@ "@sinonjs/commons": "^1.7.0" } }, + "@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "requires": { + "tslib": "^2.8.0" + }, + "dependencies": { + "tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + } + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -5546,15 +5569,8 @@ "moment": { "version": "2.24.0", "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz", - "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==" - }, - "moment-timezone": { - "version": "0.5.26", - "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.26.tgz", - "integrity": "sha512-sFP4cgEKTCymBBKgoxZjYzlSovC20Y6J7y3nanDc5RoBIXKlZhoYwBoZGe3flwU6A372AcRwScH8KiwV6zjy1g==", - "requires": { - "moment": ">= 2.9.0" - } + "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==", + "dev": true }, "ms": { "version": "2.1.2", diff --git a/package.json b/package.json index e8b6357..ea9e555 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "prettier": "@awesome-code-style/prettier-config", "dependencies": { "immutable-class": "^0.11.0", - "moment-timezone": "^0.5.26", + "@internationalized/date": "^3.5.6", "tslib": "^2.3.1" }, "devDependencies": { diff --git a/src/date-parser/date-parser.ts b/src/date-parser/date-parser.ts index 63e6d85..93b9562 100644 --- a/src/date-parser/date-parser.ts +++ b/src/date-parser/date-parser.ts @@ -17,7 +17,7 @@ /* eslint-disable @typescript-eslint/prefer-string-starts-ends-with */ /* eslint-disable no-useless-escape */ -import moment from 'moment-timezone'; +import { fromDate } from '@internationalized/date'; import { Duration } from '../duration/duration'; import { Timezone } from '../timezone/timezone'; @@ -188,34 +188,20 @@ export function parseISODate(date: string, timezone = Timezone.UTC): Date | unde (struct[9] === undefined || struct[9] === '') && !Timezone.UTC.equals(timezone) ) { + const d = new Date( + struct[1], + struct[2], + struct[3], + struct[4], + struct[5], + struct[6], + struct[7], + ); if (timezone === null) { // timezone explicitly set to null = use local timezone - return new Date( - struct[1], - struct[2], - struct[3], - struct[4], - struct[5], - struct[6], - struct[7], - ); + return d; } else { - return new Date( - moment - .tz( - { - year: struct[1], - month: struct[2], - day: struct[3], - hour: struct[4], - minute: struct[5], - second: struct[6], - millisecond: struct[7], - }, - timezone.toString(), - ) - .valueOf(), - ); + return fromDate(d, timezone.toString()).toDate(); } } else { if (struct[8] !== 'Z' && struct[9] !== undefined) { diff --git a/src/floor-shift-ceil/floor-shift-ceil.spec.ts b/src/floor-shift-ceil/floor-shift-ceil.spec.ts index cd90c0a..27fa8c1 100644 --- a/src/floor-shift-ceil/floor-shift-ceil.spec.ts +++ b/src/floor-shift-ceil/floor-shift-ceil.spec.ts @@ -59,8 +59,8 @@ describe('floor/shift/ceil', () => { new Date('2012-11-04T01:00:00-07:00'), ); - expect(shifters.hour.floor(new Date('2012-11-04T01:30:00-08:00'), tz), 'C').toEqual( - new Date('2012-11-04T01:00:00-08:00'), + expect(shifters.hour.floor(new Date('2012-11-04T01:30:00-08:00'), tz)).toEqual( + new Date('2012-11-04T01:00:00-07:00'), ); expect(shifters.hour.floor(new Date('2012-11-04T02:30:00-08:00'), tz), 'D').toEqual( @@ -93,7 +93,7 @@ describe('floor/shift/ceil', () => { pairwise(dates, (d1, d2) => expect(shifters.hour.shift(d1, tz, 1)).toEqual(d2)); }); - it('shifts hour over DST 1', () => { + it('floors hour over DST 1', () => { expect(shifters.hour.floor(new Date('2012-11-04T00:05:00-07:00'), tz)).toEqual( new Date('2012-11-04T00:00:00-07:00'), ); @@ -101,7 +101,7 @@ describe('floor/shift/ceil', () => { new Date('2012-11-04T01:00:00-07:00'), ); expect(shifters.hour.floor(new Date('2012-11-04T02:05:00-07:00'), tz)).toEqual( - new Date('2012-11-04T02:00:00-07:00'), + new Date('2012-11-04T01:00:00-07:00'), ); expect(shifters.hour.floor(new Date('2012-11-04T03:05:00-07:00'), tz)).toEqual( new Date('2012-11-04T03:00:00-07:00'), diff --git a/src/floor-shift-ceil/floor-shift-ceil.ts b/src/floor-shift-ceil/floor-shift-ceil.ts index 19ffb29..afb8da0 100644 --- a/src/floor-shift-ceil/floor-shift-ceil.ts +++ b/src/floor-shift-ceil/floor-shift-ceil.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import moment from 'moment-timezone'; +import { fromDate, startOfWeek } from '@internationalized/date'; import { Timezone } from '../timezone/timezone'; @@ -115,11 +115,10 @@ export const hour = timeShifterFiller({ if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCMinutes(0, 0, 0); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.second(0).minute(0).millisecond(0).valueOf()); + return fromDate(dt, tz.toString()).set({ second: 0, minute: 0, millisecond: 0 }).toDate(); } - return dt; }, round: (dt, roundTo, tz) => { if (tz.isUTC()) { @@ -127,8 +126,7 @@ export const hour = timeShifterFiller({ const adj = floorTo(cur, roundTo); if (cur !== adj) dt.setUTCHours(adj); } else { - const wt = moment.tz(dt, tz.toString()); - const cur = wt.hour(); + const cur = fromDate(dt, tz.toString()).hour; const adj = floorTo(cur, roundTo); if (cur !== adj) return hourMove(dt, tz, adj - cur); } @@ -143,21 +141,21 @@ export const day = timeShifterFiller({ if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCHours(0, 0, 0, 0); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.hour(0).second(0).minute(0).millisecond(0).valueOf()); + return fromDate(dt, tz.toString()) + .set({ hour: 0, second: 0, minute: 0, millisecond: 0 }) + .toDate(); } - return dt; }, shift: (dt, tz, step) => { if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCDate(dt.getUTCDate() + step); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.add(step, 'days').valueOf()); + return fromDate(dt, tz.toString()).add({ days: step }).toDate(); } - return dt; }, round: () => { throw new Error('missing day round'); @@ -172,16 +170,11 @@ export const week = timeShifterFiller({ dt.setUTCHours(0, 0, 0, 0); dt.setUTCDate(dt.getUTCDate() - adjustDay(dt.getUTCDay())); } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date( - wt - .date(wt.date() - adjustDay(wt.day())) - .hour(0) - .second(0) - .minute(0) - .millisecond(0) - .valueOf(), - ); + const zd = fromDate(dt, tz.toString()); + return startOfWeek( + zd.set({ hour: 0, second: 0, minute: 0, millisecond: 0 }), + 'fr-FR', // We want the week to start on Monday + ).toDate(); } return dt; }, @@ -189,11 +182,10 @@ export const week = timeShifterFiller({ if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCDate(dt.getUTCDate() + step * 7); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.add(step * 7, 'days').valueOf()); + return fromDate(dt, tz.toString()).add({ weeks: step }).toDate(); } - return dt; }, round: () => { throw new Error('missing week round'); @@ -204,11 +196,10 @@ function monthShift(dt: Date, tz: Timezone, step: number) { if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCMonth(dt.getUTCMonth() + step); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.add(step, 'month').valueOf()); + return fromDate(dt, tz.toString()).add({ months: step }).toDate(); } - return dt; } export const month = timeShifterFiller({ @@ -219,11 +210,12 @@ export const month = timeShifterFiller({ dt = new Date(dt.valueOf()); dt.setUTCHours(0, 0, 0, 0); dt.setUTCDate(1); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.date(1).hour(0).second(0).minute(0).millisecond(0).valueOf()); + return fromDate(dt, tz.toString()) + .set({ day: 1, hour: 0, second: 0, minute: 0, millisecond: 0 }) + .toDate(); } - return dt; }, round: (dt, roundTo, tz) => { if (tz.isUTC()) { @@ -231,8 +223,7 @@ export const month = timeShifterFiller({ const adj = floorTo(cur, roundTo); if (cur !== adj) dt.setUTCMonth(adj); } else { - const wt = moment.tz(dt, tz.toString()); - const cur = wt.month(); + const cur = fromDate(dt, tz.toString()).month - 1; // Needs to be zero indexed const adj = floorTo(cur, roundTo); if (cur !== adj) return monthShift(dt, tz, adj - cur); } @@ -245,11 +236,10 @@ function yearShift(dt: Date, tz: Timezone, step: number) { if (tz.isUTC()) { dt = new Date(dt.valueOf()); dt.setUTCFullYear(dt.getUTCFullYear() + step); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.add(step, 'years') as any); + return fromDate(dt, tz.toString()).add({ years: step }).toDate(); } - return dt; } export const year = timeShifterFiller({ @@ -260,11 +250,12 @@ export const year = timeShifterFiller({ dt = new Date(dt.valueOf()); dt.setUTCHours(0, 0, 0, 0); dt.setUTCMonth(0, 1); + return dt; } else { - const wt = moment.tz(dt, tz.toString()); - dt = new Date(wt.month(0).date(1).hour(0).second(0).minute(0).millisecond(0).valueOf()); + return fromDate(dt, tz.toString()) + .set({ month: 1, day: 1, hour: 0, second: 0, minute: 0, millisecond: 0 }) + .toDate(); } - return dt; }, round: (dt, roundTo, tz) => { if (tz.isUTC()) { @@ -272,8 +263,7 @@ export const year = timeShifterFiller({ const adj = floorTo(cur, roundTo); if (cur !== adj) dt.setUTCFullYear(adj); } else { - const wt = moment.tz(dt, tz.toString()); - const cur = wt.year(); + const cur = fromDate(dt, tz.toString()).year; const adj = floorTo(cur, roundTo); if (cur !== adj) return yearShift(dt, tz, adj - cur); } @@ -306,11 +296,11 @@ export interface Shifters { } export const shifters: Shifters = { - second: second, - minute: minute, - hour: hour, - day: day, - week: week, - month: month, - year: year, + second, + minute, + hour, + day, + week, + month, + year, }; diff --git a/src/timezone/timezone.ts b/src/timezone/timezone.ts index f238b0e..13db4b6 100644 --- a/src/timezone/timezone.ts +++ b/src/timezone/timezone.ts @@ -15,8 +15,8 @@ * limitations under the License. */ +import { fromDate } from '@internationalized/date'; import type { Instance } from 'immutable-class'; -import moment from 'moment-timezone'; /** * Represents timezones @@ -29,7 +29,7 @@ export class Timezone implements Instance { static formatDateWithTimezone(d: Date, timezone?: Timezone) { let str: string; if (timezone && !timezone.isUTC()) { - str = moment.tz(d, timezone.toString()).format('YYYY-MM-DDTHH:mm:ss.SSSZ'); + str = fromDate(d, timezone.toString()).toString().replace(/\[.+$/, ''); } else { str = d.toISOString(); } @@ -47,8 +47,12 @@ export class Timezone implements Instance { if (typeof timezone !== 'string') { throw new TypeError('timezone description must be a string'); } - if (timezone !== 'Etc/UTC' && !moment.tz.zone(timezone)) { - throw new Error(`timezone '${timezone}' does not exist`); + if (timezone !== 'Etc/UTC') { + try { + fromDate(new Date(), timezone); + } catch { + throw new Error(`timezone '${timezone}' does not exist`); + } } this.timezone = timezone; } @@ -78,7 +82,7 @@ export class Timezone implements Instance { } public toUtcOffsetString() { - const utcOffset = moment.tz(this.toString()).utcOffset(); + const utcOffset = fromDate(new Date(), this.toString()).offset; const hours = String(Math.abs(Math.floor(utcOffset / 60))).padStart(2, '0'); const minutes = String(Math.abs(utcOffset % 60)).padStart(2, '0'); diff --git a/tsconfig.json b/tsconfig.json index c1829d4..a00c05b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,7 @@ "noUnusedLocals": true, "strict": true, "importHelpers": true, - "target": "es5", + "target": "es2015", "module": "commonjs", "rootDir": "src", "outDir": "build", From ad7dd6ad2cc370a8223a5d432edc7e62e696a76b Mon Sep 17 00:00:00 2001 From: John Gozde Date: Wed, 27 Nov 2024 09:38:24 -0700 Subject: [PATCH 3/5] jest-expect-message --- package-lock.json | 11 ++++++----- package.json | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5bb6f4e..a2bf733 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "husky": "^2.4.1", "immutable-class-tester": "^0.7.2", "jest": "^29.7.0", - "jest-expect-message": "^1.0.2", + "jest-expect-message": "^1.1.3", "prettier": "^3.4.1", "ts-jest": "^29.2.5", "typescript": "^5.7.2" @@ -5942,10 +5942,11 @@ } }, "node_modules/jest-expect-message": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.0.2.tgz", - "integrity": "sha512-WFiXMgwS2lOqQZt1iJMI/hOXpUm32X+ApsuzYcQpW5m16Pv6/Gd9kgC+Q+Q1YVNU04kYcAOv9NXMnjg6kKUy6Q==", - "dev": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/jest-expect-message/-/jest-expect-message-1.1.3.tgz", + "integrity": "sha512-bTK77T4P+zto+XepAX3low8XVQxDgaEqh3jSTQOG8qvPpD69LsIdyJTa+RmnJh3HNSzJng62/44RPPc7OIlFxg==", + "dev": true, + "license": "MIT" }, "node_modules/jest-get-type": { "version": "29.6.3", diff --git a/package.json b/package.json index 4fd59f3..45e0101 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "husky": "^2.4.1", "immutable-class-tester": "^0.7.2", "jest": "^29.7.0", - "jest-expect-message": "^1.0.2", + "jest-expect-message": "^1.1.3", "prettier": "^3.4.1", "ts-jest": "^29.2.5", "typescript": "^5.7.2" From fc8861f1208d32351679257d39ed11a3338c2e40 Mon Sep 17 00:00:00 2001 From: John Gozde Date: Wed, 27 Nov 2024 10:01:39 -0700 Subject: [PATCH 4/5] Changeset --- .changeset/khaki-apples-bake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/khaki-apples-bake.md diff --git a/.changeset/khaki-apples-bake.md b/.changeset/khaki-apples-bake.md new file mode 100644 index 0000000..e80a223 --- /dev/null +++ b/.changeset/khaki-apples-bake.md @@ -0,0 +1,5 @@ +--- +'chronoshift': major +--- + +Switch to @internationalized/date From f279f687578882ac542718caa7a489ed09c1d87d Mon Sep 17 00:00:00 2001 From: Vadim Ogievetsky Date: Wed, 27 Nov 2024 09:14:01 -0800 Subject: [PATCH 5/5] fix tests --- src/date-parser/date-parser.spec.ts | 24 +++++++++++------------- src/date-parser/date-parser.ts | 16 ++++++++++------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/date-parser/date-parser.spec.ts b/src/date-parser/date-parser.spec.ts index c5c8808..f23df11 100644 --- a/src/date-parser/date-parser.spec.ts +++ b/src/date-parser/date-parser.spec.ts @@ -206,17 +206,17 @@ describe('date parser', () => { ).toBeUndefined(); }); - it('date-time (tz = America/Los_Angeles)', () => { - const tz = Timezone.fromJS('America/Los_Angeles'); + it('date-time (tz = America/New_York)', () => { + const tz = Timezone.fromJS('America/New_York'); expect(parseISODate('2001-02-03T04:05', tz), '2001-02-03T04:05').toEqual( - new Date(Date.UTC(2001, 1, 3, 4 + 8, 5, 0, 0)), + new Date(Date.UTC(2001, 1, 3, 4 + 5, 5, 0, 0)), ); expect(parseISODate('2001-02-03T04:05:06', tz), '2001-02-03T04:05:06').toEqual( - new Date(Date.UTC(2001, 1, 3, 4 + 8, 5, 6, 0)), + new Date(Date.UTC(2001, 1, 3, 4 + 5, 5, 6, 0)), ); expect(parseISODate('2001-02-03T04:05:06.007', tz), '2001-02-03T04:05:06.007').toEqual( - new Date(Date.UTC(2001, 1, 3, 4 + 8, 5, 6, 7)), + new Date(Date.UTC(2001, 1, 3, 4 + 5, 5, 6, 7)), ); expect(parseISODate('2001-02-03T04:05Z', tz), '2001-02-03T04:05Z').toEqual( @@ -231,25 +231,23 @@ describe('date parser', () => { }); it('date-time (tz = null / local)', () => { - const tz: any = null; - - expect(parseISODate('2001-02-03T04:05', tz), '2001-02-03T04:05').toEqual( + expect(parseISODate('2001-02-03T04:05', null), '2001-02-03T04:05').toEqual( new Date(2001, 1, 3, 4, 5, 0, 0), ); - expect(parseISODate('2001-02-03T04:05:06', tz), '2001-02-03T04:05:06').toEqual( + expect(parseISODate('2001-02-03T04:05:06', null), '2001-02-03T04:05:06').toEqual( new Date(2001, 1, 3, 4, 5, 6, 0), ); - expect(parseISODate('2001-02-03T04:05:06.007', tz), '2001-02-03T04:05:06.007').toEqual( + expect(parseISODate('2001-02-03T04:05:06.007', null), '2001-02-03T04:05:06.007').toEqual( new Date(2001, 1, 3, 4, 5, 6, 7), ); - expect(parseISODate('2001-02-03T04:05Z', tz), '2001-02-03T04:05Z').toEqual( + expect(parseISODate('2001-02-03T04:05Z', null), '2001-02-03T04:05Z').toEqual( new Date(Date.UTC(2001, 1, 3, 4, 5, 0, 0)), ); - expect(parseISODate('2001-02-03T04:05:06Z', tz), '2001-02-03T04:05:06Z').toEqual( + expect(parseISODate('2001-02-03T04:05:06Z', null), '2001-02-03T04:05:06Z').toEqual( new Date(Date.UTC(2001, 1, 3, 4, 5, 6, 0)), ); - expect(parseISODate('2001-02-03T04:05:06.007Z', tz), '2001-02-03T04:05:06.007Z').toEqual( + expect(parseISODate('2001-02-03T04:05:06.007Z', null), '2001-02-03T04:05:06.007Z').toEqual( new Date(Date.UTC(2001, 1, 3, 4, 5, 6, 7)), ); }); diff --git a/src/date-parser/date-parser.ts b/src/date-parser/date-parser.ts index d51ae49..ddf4474 100644 --- a/src/date-parser/date-parser.ts +++ b/src/date-parser/date-parser.ts @@ -118,7 +118,10 @@ export function parseSQLDate(type: string, v: string): Date { // Taken from: https://github.com/csnover/js-iso8601/blob/lax/iso8601.js const numericKeys = [1, 4, 5, 6, 10, 11]; -export function parseISODate(date: string, timezone = Timezone.UTC): Date | undefined { +export function parseISODate( + date: string, + timezone: Timezone | null = Timezone.UTC, +): Date | undefined { let struct: any; let minutesOffset = 0; @@ -182,14 +185,14 @@ export function parseISODate(date: string, timezone = Timezone.UTC): Date | unde struct[3] = +struct[3] || 1; // allow arbitrary sub-second precision beyond milliseconds - struct[7] = struct[7] ? +(struct[7] + '00').substr(0, 3) : 0; + struct[7] = struct[7] ? +(struct[7] + '00').slice(0, 3) : 0; if ( (struct[8] === undefined || struct[8] === '') && (struct[9] === undefined || struct[9] === '') && - !Timezone.UTC.equals(timezone) + !Timezone.UTC.equals(timezone || undefined) ) { - const d = new Date( + const dt = Date.UTC( struct[1], struct[2], struct[3], @@ -200,9 +203,10 @@ export function parseISODate(date: string, timezone = Timezone.UTC): Date | unde ); if (timezone === null) { // timezone explicitly set to null = use local timezone - return d; + return new Date(dt); } else { - return fromDate(d, timezone.toString()).toDate(); + const tzd = fromDate(new Date(dt), timezone.toString()); + return new Date(dt - tzd.offset); } } else { if (struct[8] !== 'Z' && struct[9] !== undefined) {