UNPKG

zoned-date-time

Version:

A tiny JavaScript Date with full IANA timezone support

110 lines (94 loc) 3.65 kB
function definePrivateProperty(object, property, value) { Object.defineProperty(object, property, { value: value }); } function getUntilsIndex(original, untils) { var index = 0; var originalTime = original.getTime(); // TODO Should we do binary search for improved performance? while (index < untils.length - 1 && originalTime >= untils[index]) { index++; } return index; } function setWrap(fn) { var offset1 = this.getTimezoneOffset(); var ret = fn(); this.original.setTime(new Date(this.getTime())); var offset2 = this.getTimezoneOffset(); if (offset2 - offset1) { this.original.setMinutes(this.original.getMinutes() + offset2 - offset1); } return ret; } var ZonedDateTime = function(date, timeZoneData) { definePrivateProperty(this, "original", new Date(date.getTime())); definePrivateProperty(this, "local", new Date(date.getTime())); definePrivateProperty(this, "timeZoneData", timeZoneData); definePrivateProperty(this, "setWrap", setWrap); if (!(timeZoneData.untils && timeZoneData.offsets && timeZoneData.isdsts)) { throw new Error("Invalid IANA data"); } this.setTime(this.local.getTime() - this.getTimezoneOffset() * 60 * 1000); }; ZonedDateTime.prototype.clone = function() { return new ZonedDateTime(this.original, this.timeZoneData); }; // Date field getters. ["getFullYear", "getMonth", "getDate", "getDay", "getHours", "getMinutes", "getSeconds", "getMilliseconds"].forEach(function(method) { // Corresponding UTC method, e.g., "getUTCFullYear" if method === "getFullYear". var utcMethod = "getUTC" + method.substr(3); ZonedDateTime.prototype[method] = function() { return this.local[utcMethod](); }; }); // Note: Define .valueOf = .getTime for arithmetic operations like date1 - date2. ZonedDateTime.prototype.valueOf = ZonedDateTime.prototype.getTime = function() { return this.local.getTime() + this.getTimezoneOffset() * 60 * 1000; }; ZonedDateTime.prototype.getTimezoneOffset = function() { var index = getUntilsIndex(this.original, this.timeZoneData.untils); return this.timeZoneData.offsets[index]; }; // Date field setters. ["setFullYear", "setMonth", "setDate", "setHours", "setMinutes", "setSeconds", "setMilliseconds"].forEach(function(method) { // Corresponding UTC method, e.g., "setUTCFullYear" if method === "setFullYear". var utcMethod = "setUTC" + method.substr(3); ZonedDateTime.prototype[method] = function(value) { var local = this.local; // Note setWrap is needed for seconds and milliseconds just because // abs(value) could be >= a minute. return this.setWrap(function() { return local[utcMethod](value); }); }; }); ZonedDateTime.prototype.setTime = function(time) { return this.local.setTime(time); }; ZonedDateTime.prototype.isDST = function() { var index = getUntilsIndex(this.original, this.timeZoneData.untils); return Boolean(this.timeZoneData.isdsts[index]); }; ZonedDateTime.prototype.inspect = function() { var index = getUntilsIndex(this.original, this.timeZoneData.untils); var abbrs = this.timeZoneData.abbrs; return this.local.toISOString().replace(/Z$/, "") + " " + (abbrs && abbrs[index] + " " || (this.getTimezoneOffset() * -1) + " ") + (this.isDST() ? "(daylight savings)" : ""); }; ZonedDateTime.prototype.toDate = function() { return new Date(this.getTime()); }; // Type cast getters. ["toISOString", "toJSON", "toUTCString"].forEach(function(method) { ZonedDateTime.prototype[method] = function() { return this.toDate()[method](); }; }); if (typeof module !== "undefined" && module.exports) { module.exports = ZonedDateTime; }