From f6c88d0629ee255c32db32f8de91161fe876577d Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Wed, 28 Dec 2016 10:32:08 -0800 Subject: [PATCH] fix dates crossing DST boundaries for UTC, closes #71 --- Makefile | 4 ++-- strftime.js | 9 ++++++++- test.js | 20 ++++++++++++++++---- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 9a5354d..4a2b985 100644 --- a/Makefile +++ b/Makefile @@ -6,10 +6,10 @@ real-minify: strftime.js test: TZ=America/Vancouver node test.js - TZ=CET node test.js + TZ=Europe/Amsterdam node test.js test-minified: minify TZ=America/Vancouver node test.js ./strftime-min.js - TZ=CET node test.js ./strftime-min.js + TZ=Europe/Amsterdam node test.js ./strftime-min.js .PHONY: test test-minified diff --git a/strftime.js b/strftime.js index 1dfcc4f..0afda93 100644 --- a/strftime.js +++ b/strftime.js @@ -183,7 +183,14 @@ timestamp = date.getTime(); if (_useUtcBasedDate) { - date = new Date(date.getTime() + getTimestampToUtcOffsetFor(date) + _customTimezoneOffset); + var utcOffset = getTimestampToUtcOffsetFor(date); + date = new Date(timestamp + utcOffset + _customTimezoneOffset); + // If we've crossed a DST boundary with this calculation we need to + // adjust the new date accordingly or it will be off by an hour in UTC. + if (getTimestampToUtcOffsetFor(date) !== utcOffset) { + var newUTCOffset = getTimestampToUtcOffsetFor(date); + date = new Date(timestamp + newUTCOffset + _customTimezoneOffset); + } } } diff --git a/test.js b/test.js index 17efa56..9fb999c 100755 --- a/test.js +++ b/test.js @@ -42,7 +42,7 @@ ok('Exports'); /// time zones if (process.env.TZ == 'America/Vancouver') { - testTimezone('P[DS]T'); + testTimezone('America/Vancouver'); assert.format('%C', '01', '01', new Date(100, 0, 1)); assert.format('%X', '11:51:45', '18:51:45'); assert.format('%c', 'Tue Jun 07 11:51:45 2011', 'Tue Jun 07 18:51:45 2011'); @@ -52,10 +52,16 @@ if (process.env.TZ == 'America/Vancouver') { assert.format('%U', '12', '13', new Date('2017-03-26 00:00:00 +0000')); assert.format('%U', '13', null, new Date('2017-03-27 00:00:00 +0000')); assert.format('%U', '13', '14', new Date('2017-04-02 00:00:00 +0000')); + + // Test dates crossing a DST boundary. + var dstStart = +new Date('2016-11-06 01:50:00'); + assert.format('%T', '01:50:00', '08:50:00', new Date(dstStart)) + assert.format('%T', '01:00:00', '09:00:00', new Date(dstStart + 10 * 60 * 1000)) + ok('Time zones (' + process.env.TZ + ')'); } -else if (process.env.TZ == 'CET') { - testTimezone('CES?T'); +else if (process.env.TZ == 'Europe/Amsterdam') { + testTimezone('Europe/Amsterdam'); assert.format('%C', '01', '00', new Date(100, 0, 1)); assert.format('%X', '20:51:45', '18:51:45'); assert.format('%c', 'Tue Jun 07 20:51:45 2011', 'Tue Jun 07 18:51:45 2011'); @@ -65,10 +71,16 @@ else if (process.env.TZ == 'CET') { assert.format('%U', '13', null, new Date('2017-03-26 00:00:00 +0000')); assert.format('%U', '13', null, new Date('2017-03-27 00:00:00 +0000')); assert.format('%U', '14', null, new Date('2017-04-02 00:00:00 +0000')); + + // Test dates crossing a DST boundary. + var dstStart = +new Date('2016-10-30 02:50:00'); + assert.format('%T', '02:50:00', '00:50:00', new Date(dstStart)) + assert.format('%T', '02:00:00', '01:00:00', new Date(dstStart + 10 * 60 * 1000)) + ok('Time zones (' + process.env.TZ + ')'); } else { - console.log('(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')'); + assert(false, '(Current timezone has no tests: ' + (process.env.TZ || 'none') + ')'); } /// check all formats in GMT, most coverage