diff options
Diffstat (limited to 'src/modules/dayjs/plugin/timezone/index.js')
-rw-r--r-- | src/modules/dayjs/plugin/timezone/index.js | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/src/modules/dayjs/plugin/timezone/index.js b/src/modules/dayjs/plugin/timezone/index.js new file mode 100644 index 0000000..a7bd673 --- /dev/null +++ b/src/modules/dayjs/plugin/timezone/index.js @@ -0,0 +1,188 @@ +/** + * Copy from node_modules/dayjs/plugin/timezone.js + * Try to fix https://github.com/louislam/uptime-kuma/issues/2318 + * Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc + * License: MIT + */ +import { MIN, MS } from "../../constant"; +let typeToPos = { + year: 0, + month: 1, + day: 2, + hour: 3, + minute: 4, + second: 5 +}; // Cache time-zone lookups from Intl.DateTimeFormat, +// as it is a *very* slow method. + +let dtfCache = {}; + +let getDateTimeFormat = function getDateTimeFormat(timezone, options) { + if (options === void 0) { + options = {}; + } + + let timeZoneName = options.timeZoneName || "short"; + let key = timezone + "|" + timeZoneName; + let dtf = dtfCache[key]; + + if (!dtf) { + dtf = new Intl.DateTimeFormat("en-US", { + hour12: false, + timeZone: timezone, + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + second: "2-digit", + timeZoneName: timeZoneName + }); + dtfCache[key] = dtf; + } + + return dtf; +}; + +export default (function (o, c, d) { + let defaultTimezone; + + let makeFormatParts = function makeFormatParts(timestamp, timezone, options) { + if (options === void 0) { + options = {}; + } + + let date = new Date(timestamp); + let dtf = getDateTimeFormat(timezone, options); + return dtf.formatToParts(date); + }; + + let tzOffset = function tzOffset(timestamp, timezone) { + let formatResult = makeFormatParts(timestamp, timezone); + let filled = []; + + for (let i = 0; i < formatResult.length; i += 1) { + let _formatResult$i = formatResult[i]; + let type = _formatResult$i.type; + let value = _formatResult$i.value; + let pos = typeToPos[type]; + + if (pos >= 0) { + filled[pos] = parseInt(value, 10); + } + } + + let hour = filled[3]; // Workaround for the same behavior in different node version + // https://github.com/nodejs/node/issues/33027 + + /* istanbul ignore next */ + + let fixedHour = hour === 24 ? 0 : hour; + let utcString = filled[0] + "-" + filled[1] + "-" + filled[2] + " " + fixedHour + ":" + filled[4] + ":" + filled[5] + ":000"; + let utcTs = d.utc(utcString).valueOf(); + let asTS = +timestamp; + let over = asTS % 1000; + asTS -= over; + return (utcTs - asTS) / (60 * 1000); + }; // find the right offset a given local time. The o input is our guess, which determines which + // offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST) + // https://github.com/moment/luxon/blob/master/src/datetime.js#L76 + + let fixOffset = function fixOffset(localTS, o0, tz) { + // Our UTC time is just a guess because our offset is just a guess + let utcGuess = localTS - o0 * 60 * 1000; // Test whether the zone matches the offset for this ts + + let o2 = tzOffset(utcGuess, tz); // If so, offset didn't change and we're done + + if (o0 === o2) { + return [ utcGuess, o0 ]; + } // If not, change the ts by the difference in the offset + + utcGuess -= (o2 - o0) * 60 * 1000; // If that gives us the local time we want, we're done + + let o3 = tzOffset(utcGuess, tz); + + if (o2 === o3) { + return [ utcGuess, o2 ]; + } // If it's different, we're in a hole time. + // The offset has changed, but the we don't adjust the time + + return [ localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3) ]; + }; + + let proto = c.prototype; + + proto.tz = function (timezone, keepLocalTime) { + if (timezone === void 0) { + timezone = defaultTimezone; + } + + let oldOffset = this.utcOffset(); + let date = this.toDate(); + let target = date.toLocaleString("en-US", { + timeZone: timezone + }).replace("\u202f", " "); + let diff = Math.round((date - new Date(target)) / 1000 / 60); + let ins = d(target).$set(MS, this.$ms).utcOffset(-Math.round(date.getTimezoneOffset() / 15) * 15 - diff, true); + + if (keepLocalTime) { + let newOffset = ins.utcOffset(); + ins = ins.add(oldOffset - newOffset, MIN); + } + + ins.$x.$timezone = timezone; + return ins; + }; + + proto.offsetName = function (type) { + // type: short(default) / long + let zone = this.$x.$timezone || d.tz.guess(); + let result = makeFormatParts(this.valueOf(), zone, { + timeZoneName: type + }).find(function (m) { + return m.type.toLowerCase() === "timezonename"; + }); + return result && result.value; + }; + + let oldStartOf = proto.startOf; + + proto.startOf = function (units, startOf) { + if (!this.$x || !this.$x.$timezone) { + return oldStartOf.call(this, units, startOf); + } + + let withoutTz = d(this.format("YYYY-MM-DD HH:mm:ss:SSS")); + let startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf); + return startOfWithoutTz.tz(this.$x.$timezone, true); + }; + + d.tz = function (input, arg1, arg2) { + let parseFormat = arg2 && arg1; + let timezone = arg2 || arg1 || defaultTimezone; + let previousOffset = tzOffset(+d(), timezone); + + if (typeof input !== "string") { + // timestamp number || js Date || Day.js + return d(input).tz(timezone); + } + + let localTs = d.utc(input, parseFormat).valueOf(); + + let _fixOffset = fixOffset(localTs, previousOffset, timezone); + let targetTs = _fixOffset[0]; + let targetOffset = _fixOffset[1]; + + let ins = d(targetTs).utcOffset(targetOffset); + ins.$x.$timezone = timezone; + return ins; + }; + + d.tz.guess = function () { + return Intl.DateTimeFormat().resolvedOptions().timeZone; + }; + + d.tz.setDefault = function (timezone) { + defaultTimezone = timezone; + }; +}); |