diff options
| author | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
|---|---|---|
| committer | Shipwreckt <me@shipwreckt.co.uk> | 2025-10-31 20:02:14 +0000 |
| commit | 7a52ddeba2a68388b544f529d2d92104420f77b0 (patch) | |
| tree | 15ddd47457a2cb4a96060747437d36474e4f6b4e /node_modules/luxon/src/zones | |
| parent | 53d6ae2b5568437afa5e4995580a3fb679b7b91b (diff) | |
Changed from static to 11ty!
Diffstat (limited to 'node_modules/luxon/src/zones')
| -rw-r--r-- | node_modules/luxon/src/zones/IANAZone.js | 235 | ||||
| -rw-r--r-- | node_modules/luxon/src/zones/fixedOffsetZone.js | 150 | ||||
| -rw-r--r-- | node_modules/luxon/src/zones/invalidZone.js | 53 | ||||
| -rw-r--r-- | node_modules/luxon/src/zones/systemZone.js | 61 |
4 files changed, 499 insertions, 0 deletions
diff --git a/node_modules/luxon/src/zones/IANAZone.js b/node_modules/luxon/src/zones/IANAZone.js new file mode 100644 index 0000000..aa3d375 --- /dev/null +++ b/node_modules/luxon/src/zones/IANAZone.js @@ -0,0 +1,235 @@ +import { formatOffset, parseZoneInfo, isUndefined, objToLocalTS } from "../impl/util.js"; +import Zone from "../zone.js"; + +const dtfCache = new Map(); +function makeDTF(zoneName) { + let dtf = dtfCache.get(zoneName); + if (dtf === undefined) { + dtf = new Intl.DateTimeFormat("en-US", { + hour12: false, + timeZone: zoneName, + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + era: "short", + }); + dtfCache.set(zoneName, dtf); + } + return dtf; +} + +const typeToPos = { + year: 0, + month: 1, + day: 2, + era: 3, + hour: 4, + minute: 5, + second: 6, +}; + +function hackyOffset(dtf, date) { + const formatted = dtf.format(date).replace(/\u200E/g, ""), + parsed = /(\d+)\/(\d+)\/(\d+) (AD|BC),? (\d+):(\d+):(\d+)/.exec(formatted), + [, fMonth, fDay, fYear, fadOrBc, fHour, fMinute, fSecond] = parsed; + return [fYear, fMonth, fDay, fadOrBc, fHour, fMinute, fSecond]; +} + +function partsOffset(dtf, date) { + const formatted = dtf.formatToParts(date); + const filled = []; + for (let i = 0; i < formatted.length; i++) { + const { type, value } = formatted[i]; + const pos = typeToPos[type]; + + if (type === "era") { + filled[pos] = value; + } else if (!isUndefined(pos)) { + filled[pos] = parseInt(value, 10); + } + } + return filled; +} + +const ianaZoneCache = new Map(); +/** + * A zone identified by an IANA identifier, like America/New_York + * @implements {Zone} + */ +export default class IANAZone extends Zone { + /** + * @param {string} name - Zone name + * @return {IANAZone} + */ + static create(name) { + let zone = ianaZoneCache.get(name); + if (zone === undefined) { + ianaZoneCache.set(name, (zone = new IANAZone(name))); + } + return zone; + } + + /** + * Reset local caches. Should only be necessary in testing scenarios. + * @return {void} + */ + static resetCache() { + ianaZoneCache.clear(); + dtfCache.clear(); + } + + /** + * Returns whether the provided string is a valid specifier. This only checks the string's format, not that the specifier identifies a known zone; see isValidZone for that. + * @param {string} s - The string to check validity on + * @example IANAZone.isValidSpecifier("America/New_York") //=> true + * @example IANAZone.isValidSpecifier("Sport~~blorp") //=> false + * @deprecated For backward compatibility, this forwards to isValidZone, better use `isValidZone()` directly instead. + * @return {boolean} + */ + static isValidSpecifier(s) { + return this.isValidZone(s); + } + + /** + * Returns whether the provided string identifies a real zone + * @param {string} zone - The string to check + * @example IANAZone.isValidZone("America/New_York") //=> true + * @example IANAZone.isValidZone("Fantasia/Castle") //=> false + * @example IANAZone.isValidZone("Sport~~blorp") //=> false + * @return {boolean} + */ + static isValidZone(zone) { + if (!zone) { + return false; + } + try { + new Intl.DateTimeFormat("en-US", { timeZone: zone }).format(); + return true; + } catch (e) { + return false; + } + } + + constructor(name) { + super(); + /** @private **/ + this.zoneName = name; + /** @private **/ + this.valid = IANAZone.isValidZone(name); + } + + /** + * The type of zone. `iana` for all instances of `IANAZone`. + * @override + * @type {string} + */ + get type() { + return "iana"; + } + + /** + * The name of this zone (i.e. the IANA zone name). + * @override + * @type {string} + */ + get name() { + return this.zoneName; + } + + /** + * Returns whether the offset is known to be fixed for the whole year: + * Always returns false for all IANA zones. + * @override + * @type {boolean} + */ + get isUniversal() { + return false; + } + + /** + * Returns the offset's common name (such as EST) at the specified timestamp + * @override + * @param {number} ts - Epoch milliseconds for which to get the name + * @param {Object} opts - Options to affect the format + * @param {string} opts.format - What style of offset to return. Accepts 'long' or 'short'. + * @param {string} opts.locale - What locale to return the offset name in. + * @return {string} + */ + offsetName(ts, { format, locale }) { + return parseZoneInfo(ts, format, locale, this.name); + } + + /** + * Returns the offset's value as a string + * @override + * @param {number} ts - Epoch milliseconds for which to get the offset + * @param {string} format - What style of offset to return. + * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively + * @return {string} + */ + formatOffset(ts, format) { + return formatOffset(this.offset(ts), format); + } + + /** + * Return the offset in minutes for this zone at the specified timestamp. + * @override + * @param {number} ts - Epoch milliseconds for which to compute the offset + * @return {number} + */ + offset(ts) { + if (!this.valid) return NaN; + const date = new Date(ts); + + if (isNaN(date)) return NaN; + + const dtf = makeDTF(this.name); + let [year, month, day, adOrBc, hour, minute, second] = dtf.formatToParts + ? partsOffset(dtf, date) + : hackyOffset(dtf, date); + + if (adOrBc === "BC") { + year = -Math.abs(year) + 1; + } + + // because we're using hour12 and https://bugs.chromium.org/p/chromium/issues/detail?id=1025564&can=2&q=%2224%3A00%22%20datetimeformat + const adjustedHour = hour === 24 ? 0 : hour; + + const asUTC = objToLocalTS({ + year, + month, + day, + hour: adjustedHour, + minute, + second, + millisecond: 0, + }); + + let asTS = +date; + const over = asTS % 1000; + asTS -= over >= 0 ? over : 1000 + over; + return (asUTC - asTS) / (60 * 1000); + } + + /** + * Return whether this Zone is equal to another zone + * @override + * @param {Zone} otherZone - the zone to compare + * @return {boolean} + */ + equals(otherZone) { + return otherZone.type === "iana" && otherZone.name === this.name; + } + + /** + * Return whether this Zone is valid. + * @override + * @type {boolean} + */ + get isValid() { + return this.valid; + } +} diff --git a/node_modules/luxon/src/zones/fixedOffsetZone.js b/node_modules/luxon/src/zones/fixedOffsetZone.js new file mode 100644 index 0000000..b1ab4ab --- /dev/null +++ b/node_modules/luxon/src/zones/fixedOffsetZone.js @@ -0,0 +1,150 @@ +import { formatOffset, signedOffset } from "../impl/util.js"; +import Zone from "../zone.js"; + +let singleton = null; + +/** + * A zone with a fixed offset (meaning no DST) + * @implements {Zone} + */ +export default class FixedOffsetZone extends Zone { + /** + * Get a singleton instance of UTC + * @return {FixedOffsetZone} + */ + static get utcInstance() { + if (singleton === null) { + singleton = new FixedOffsetZone(0); + } + return singleton; + } + + /** + * Get an instance with a specified offset + * @param {number} offset - The offset in minutes + * @return {FixedOffsetZone} + */ + static instance(offset) { + return offset === 0 ? FixedOffsetZone.utcInstance : new FixedOffsetZone(offset); + } + + /** + * Get an instance of FixedOffsetZone from a UTC offset string, like "UTC+6" + * @param {string} s - The offset string to parse + * @example FixedOffsetZone.parseSpecifier("UTC+6") + * @example FixedOffsetZone.parseSpecifier("UTC+06") + * @example FixedOffsetZone.parseSpecifier("UTC-6:00") + * @return {FixedOffsetZone} + */ + static parseSpecifier(s) { + if (s) { + const r = s.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i); + if (r) { + return new FixedOffsetZone(signedOffset(r[1], r[2])); + } + } + return null; + } + + constructor(offset) { + super(); + /** @private **/ + this.fixed = offset; + } + + /** + * The type of zone. `fixed` for all instances of `FixedOffsetZone`. + * @override + * @type {string} + */ + get type() { + return "fixed"; + } + + /** + * The name of this zone. + * All fixed zones' names always start with "UTC" (plus optional offset) + * @override + * @type {string} + */ + get name() { + return this.fixed === 0 ? "UTC" : `UTC${formatOffset(this.fixed, "narrow")}`; + } + + /** + * The IANA name of this zone, i.e. `Etc/UTC` or `Etc/GMT+/-nn` + * + * @override + * @type {string} + */ + get ianaName() { + if (this.fixed === 0) { + return "Etc/UTC"; + } else { + return `Etc/GMT${formatOffset(-this.fixed, "narrow")}`; + } + } + + /** + * Returns the offset's common name at the specified timestamp. + * + * For fixed offset zones this equals to the zone name. + * @override + */ + offsetName() { + return this.name; + } + + /** + * Returns the offset's value as a string + * @override + * @param {number} ts - Epoch milliseconds for which to get the offset + * @param {string} format - What style of offset to return. + * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively + * @return {string} + */ + formatOffset(ts, format) { + return formatOffset(this.fixed, format); + } + + /** + * Returns whether the offset is known to be fixed for the whole year: + * Always returns true for all fixed offset zones. + * @override + * @type {boolean} + */ + get isUniversal() { + return true; + } + + /** + * Return the offset in minutes for this zone at the specified timestamp. + * + * For fixed offset zones, this is constant and does not depend on a timestamp. + * @override + * @return {number} + */ + offset() { + return this.fixed; + } + + /** + * Return whether this Zone is equal to another zone (i.e. also fixed and same offset) + * @override + * @param {Zone} otherZone - the zone to compare + * @return {boolean} + */ + equals(otherZone) { + return otherZone.type === "fixed" && otherZone.fixed === this.fixed; + } + + /** + * Return whether this Zone is valid: + * All fixed offset zones are valid. + * @override + * @type {boolean} + */ + get isValid() { + return true; + } +} diff --git a/node_modules/luxon/src/zones/invalidZone.js b/node_modules/luxon/src/zones/invalidZone.js new file mode 100644 index 0000000..9a1a2d4 --- /dev/null +++ b/node_modules/luxon/src/zones/invalidZone.js @@ -0,0 +1,53 @@ +import Zone from "../zone.js"; + +/** + * A zone that failed to parse. You should never need to instantiate this. + * @implements {Zone} + */ +export default class InvalidZone extends Zone { + constructor(zoneName) { + super(); + /** @private */ + this.zoneName = zoneName; + } + + /** @override **/ + get type() { + return "invalid"; + } + + /** @override **/ + get name() { + return this.zoneName; + } + + /** @override **/ + get isUniversal() { + return false; + } + + /** @override **/ + offsetName() { + return null; + } + + /** @override **/ + formatOffset() { + return ""; + } + + /** @override **/ + offset() { + return NaN; + } + + /** @override **/ + equals() { + return false; + } + + /** @override **/ + get isValid() { + return false; + } +} diff --git a/node_modules/luxon/src/zones/systemZone.js b/node_modules/luxon/src/zones/systemZone.js new file mode 100644 index 0000000..533e663 --- /dev/null +++ b/node_modules/luxon/src/zones/systemZone.js @@ -0,0 +1,61 @@ +import { formatOffset, parseZoneInfo } from "../impl/util.js"; +import Zone from "../zone.js"; + +let singleton = null; + +/** + * Represents the local zone for this JavaScript environment. + * @implements {Zone} + */ +export default class SystemZone extends Zone { + /** + * Get a singleton instance of the local zone + * @return {SystemZone} + */ + static get instance() { + if (singleton === null) { + singleton = new SystemZone(); + } + return singleton; + } + + /** @override **/ + get type() { + return "system"; + } + + /** @override **/ + get name() { + return new Intl.DateTimeFormat().resolvedOptions().timeZone; + } + + /** @override **/ + get isUniversal() { + return false; + } + + /** @override **/ + offsetName(ts, { format, locale }) { + return parseZoneInfo(ts, format, locale); + } + + /** @override **/ + formatOffset(ts, format) { + return formatOffset(this.offset(ts), format); + } + + /** @override **/ + offset(ts) { + return -new Date(ts).getTimezoneOffset(); + } + + /** @override **/ + equals(otherZone) { + return otherZone.type === "system"; + } + + /** @override **/ + get isValid() { + return true; + } +} |
