Path: blob/main/src/resources/library/dayjs/plugins/timezone.js
12923 views
import { MIN, MS } from "./constant.js";12const typeToPos = {3year: 0,4month: 1,5day: 2,6hour: 3,7minute: 4,8second: 5,9};1011// Cache time-zone lookups from Intl.DateTimeFormat,12// as it is a *very* slow method.13const dtfCache = {};14const getDateTimeFormat = (timezone, options = {}) => {15const timeZoneName = options.timeZoneName || "short";16const key = `${timezone}|${timeZoneName}`;17let dtf = dtfCache[key];18if (!dtf) {19dtf = new Intl.DateTimeFormat("en-US", {20hour12: false,21timeZone: timezone,22year: "numeric",23month: "2-digit",24day: "2-digit",25hour: "2-digit",26minute: "2-digit",27second: "2-digit",28timeZoneName,29});30dtfCache[key] = dtf;31}32return dtf;33};3435export default (o, c, d) => {36let defaultTimezone;3738const makeFormatParts = (timestamp, timezone, options = {}) => {39const date = new Date(timestamp);40const dtf = getDateTimeFormat(timezone, options);41return dtf.formatToParts(date);42};4344const tzOffset = (timestamp, timezone) => {45const formatResult = makeFormatParts(timestamp, timezone);46const filled = [];47for (let i = 0; i < formatResult.length; i += 1) {48const { type, value } = formatResult[i];49const pos = typeToPos[type];5051if (pos >= 0) {52filled[pos] = parseInt(value, 10);53}54}55const hour = filled[3];56// Workaround for the same behavior in different node version57// https://github.com/nodejs/node/issues/3302758/* istanbul ignore next */59const fixedHour = hour === 24 ? 0 : hour;60const utcString = `${filled[0]}-${filled[1]}-${filled[2]} ${fixedHour}:${filled[4]}:${filled[5]}:000`;61const utcTs = d.utc(utcString).valueOf();62let asTS = +timestamp;63const over = asTS % 1000;64asTS -= over;65return (utcTs - asTS) / (60 * 1000);66};6768// find the right offset a given local time. The o input is our guess, which determines which69// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)70// https://github.com/moment/luxon/blob/master/src/datetime.js#L7671const fixOffset = (localTS, o0, tz) => {72// Our UTC time is just a guess because our offset is just a guess73let utcGuess = localTS - o0 * 60 * 1000;74// Test whether the zone matches the offset for this ts75const o2 = tzOffset(utcGuess, tz);76// If so, offset didn't change and we're done77if (o0 === o2) {78return [utcGuess, o0];79}80// If not, change the ts by the difference in the offset81utcGuess -= (o2 - o0) * 60 * 1000;82// If that gives us the local time we want, we're done83const o3 = tzOffset(utcGuess, tz);84if (o2 === o3) {85return [utcGuess, o2];86}87// If it's different, we're in a hole time.88// The offset has changed, but the we don't adjust the time89return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)];90};9192const proto = c.prototype;9394proto.tz = function (timezone = defaultTimezone, keepLocalTime) {95const oldOffset = this.utcOffset();96const date = this.toDate();97const target = date.toLocaleString("en-US", { timeZone: timezone });98const diff = Math.round((date - new Date(target)) / 1000 / 60);99let ins = d(target)100.$set(MS, this.$ms)101.utcOffset(-Math.round(date.getTimezoneOffset() / 15) * 15 - diff, true);102if (keepLocalTime) {103const newOffset = ins.utcOffset();104ins = ins.add(oldOffset - newOffset, MIN);105}106ins.$x.$timezone = timezone;107return ins;108};109110proto.offsetName = function (type) {111// type: short(default) / long112const zone = this.$x?.$timezone || d.tz.guess();113const result = makeFormatParts(this.valueOf(), zone, {114timeZoneName: type,115}).find((m) => m.type.toLowerCase() === "timezonename");116return result && result.value;117};118119const oldStartOf = proto.startOf;120proto.startOf = function (units, startOf) {121if (!this.$x || !this.$x.$timezone) {122return oldStartOf.call(this, units, startOf);123}124125const withoutTz = d(this.format("YYYY-MM-DD HH:mm:ss:SSS"));126const startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf);127return startOfWithoutTz.tz(this.$x.$timezone, true);128};129130d.tz = function (input, arg1, arg2) {131const parseFormat = arg2 && arg1;132const timezone = arg2 || arg1 || defaultTimezone;133const previousOffset = tzOffset(+d(), timezone);134if (typeof input !== "string") {135// timestamp number || js Date || Day.js136return d(input).tz(timezone);137}138const localTs = d.utc(input, parseFormat).valueOf();139const [targetTs, targetOffset] = fixOffset(140localTs,141previousOffset,142timezone143);144const ins = d(targetTs).utcOffset(targetOffset);145ins.$x.$timezone = timezone;146return ins;147};148149d.tz.guess = function () {150return Intl.DateTimeFormat().resolvedOptions().timeZone;151};152153d.tz.setDefault = function (timezone) {154defaultTimezone = timezone;155};156};157158159