Created
January 28, 2019 12:30
-
-
Save decatur/1cbe5dab217d359373df9b195636c634 to your computer and use it in GitHub Desktop.
JavaScript Date Pitfalls
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* In a daylight-saving time locale, this will generate 92, 96 or 100 values. | |
* This function sideways some of JavaScript Date pitfalls | |
* @param {string} localDateString | |
* Example: | |
* generateQuarterHoursForLocalDate('2019-03-31').map(function(date) { return date.toJSON() }) | |
* -> 0: "2019-03-30T23:00:00.000Z" | |
* 1: "2019-03-30T23:15:00.000Z" | |
* ... | |
* 91: "2019-03-31T21:45:00.000Z" | |
*/ | |
function generateQuarterHoursForLocalDate(localDateString) { | |
const dateParts = localDateString.split('-').map(function (part) { | |
return Number(part) | |
}); | |
// Construct new date with local timezone date parts. | |
let date = new Date(dateParts[0], dateParts[1] - 1, dateParts[2]); | |
if (isNaN(date.getTime())) { | |
throw new Error('Invalid local date: ' + localDateString); | |
} | |
const datePart = dateParts[2]; | |
const quarterHours = []; | |
while (date.getDate() === datePart) { | |
// Push cloned date. | |
quarterHours.push(new Date(date.getTime())); | |
// Important: Use UTC method! | |
date.setUTCMinutes(date.getUTCMinutes() + 15) | |
} | |
return quarterHours; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Notes about JavaScript Date Pitfalls | |
* ==================================== | |
* | |
* Javascript does not distinguish between naive dates (dates without timezone) and time zone aware dates. | |
* A Date is represented by a number, which is the millis offset to 1979-01-01, and that's it. | |
* You may be tricked to think JavaScript is timezone aware by offering most operations relative to the local | |
* timezone of your machine: If there is no UTC in the name, the probable semantic is local! | |
* | |
* Consider these two dates 1 hour apart: | |
* a) 2018-10-28T02:00+02:00 (CET summer time) | |
* b) 2018-10-28T02:00+01:00 (CET, winter time) | |
* Both have a local CET time of 2018-10-28T02:00 (ambiguity) | |
* If we test this on a machine with CET locale | |
* new Date('2018-10-28T02:00').toJSON() -> a), not b) | |
* new Date('2018-10-28T02:00').getTimezoneOffset() -> -120 | |
* Where is this specified? | |
* | |
* Pitfalls (JavaScript Date is screwed) | |
* ===================================== | |
* | |
* Parsing | |
* ======= | |
* new Date('2018-01-01').toJSON() -> 2018-01-01T00:00:00Z (parsed as UTC) | |
* new Date(2018, 0, 1).toJSON() -> 2017-12-31T23:00:00Z (parsed as local time) | |
* new Date(Date.UTC(2018, 0, 1)).toJSON() -> 2018-01-01T00:00:00Z (parsed as UTC) | |
* However, if a date has a time component but no time zone, it is parsed as local time: | |
* new Date('2018-01-01T00:00') -> 2017-12-31T23:00:00Z | |
* When parsing local dates, summer time is preferred in resolving the fall back conflict: | |
* new Date("2018-10-28T02:00").toJSON() -> "2018-10-28T00:00:00Z" | |
* | |
* Misnomer | |
* ======== | |
* Most functions should have a 'local' in their names, but they don't. For example | |
* d.getTimezoneOffset() should be d.getLocalTimezoneOffset(), because it is the offset of d in local time to UTC, | |
* for example | |
* new Date('2018-10-28T00:00Z').getTimezoneOffset() -> -120 (on a machine in CET locale) | |
* | |
* toLocal Unicode frenzy | |
* ====================== | |
* Never ever use Date.toLocalXY() methods! IE will emit non-ASCII code. | |
* | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment