Skip to content

Instantly share code, notes, and snippets.

@decatur
Created January 28, 2019 12:30
Show Gist options
  • Save decatur/1cbe5dab217d359373df9b195636c634 to your computer and use it in GitHub Desktop.
Save decatur/1cbe5dab217d359373df9b195636c634 to your computer and use it in GitHub Desktop.
JavaScript Date Pitfalls
/**
* 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;
}
/*
* 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