UNPKG

dayjs-tz-helper

Version:

Day.js 時區輔助套件,提供安全解析時區日期字串與時間戳轉換功能 (Day.js timezone helper for safe timezone date string parsing and timestamp conversion)

208 lines (188 loc) 6.98 kB
/// <reference types="dayjs/plugin/timezone.d.ts" /> /// <reference types="dayjs/plugin/utc.d.ts" /> import dayjs, { type ConfigType } from 'dayjs'; import utc from 'dayjs/plugin/utc'; import timezone from 'dayjs/plugin/timezone'; import { isFloatString } from '@lazy-num/parse-number-string'; dayjs.extend(utc); dayjs.extend(timezone); /** * 偵測結尾是否為不安全的時區偏移日期字串 * Detect if the string ends with an unsafe timezone offset date string * * 偵測結尾是否為 `.000Z`、`Z`、`+00:00` 等格式 * Detect if the string ends with `.000Z`, `Z`, `+00:00`, etc. * * @param {string} date - 日期字串 / Date string * @returns {boolean} 是否為不安全的偏移日期字串 / Whether it is an unsafe offset date string */ export function _isUnsafeOffsetDateString(date: string) { return /(?:\dZ|\+\d{2}:?\d{2})$/.test(date) } /** * 偵測是否為 UTC 或 GMT 日期字串 * Detect if it is a UTC or GMT date string * * @param {string} date - 日期字串 / Date string * @returns {boolean} 是否為 UTC/GMT 日期字串 / Whether it is a UTC/GMT date string */ export function _isUnsafeUTCDateString(date: string) { return /(?:GMT|UTC)/.test(date) } /** * 時區類型 - 支援 IANA 時區資料庫中的時區名稱 * Timezone type - supports timezone names from IANA database * * Day.js 透過 Internationalization API 支援時區,無需在程式碼中包含額外的時區資料。 * Day.js supports timezone via the Internationalization API, no extra timezone data needed in code bundle. * * @see https://day.js.org/docs/en/timezone/timezone * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones */ export type ITimezone = string | 'GMT' | 'Asia/Taipei' | 'Asia/Tokyo' | 'America/New_York'; /** * tzDayjsSafeParse 選項介面 * tzDayjsSafeParse options interface */ export interface IOptionsTzDayjsSafeParse { /** * 時區設定 * Timezone setting * * Day.js 透過 Internationalization API 支援時區,無需在程式碼中包含額外的時區資料。 * Day.js supports timezone via the Internationalization API, no extra timezone data needed in code bundle. * * @see https://day.js.org/docs/en/timezone/timezone * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones */ timezone?: ITimezone, /** * 最小有效時間戳 * Minimum valid timestamp * * 若設為 `true` 或 `0`,代表 `1970-01-01T00:00:00.000Z` * If set to `true` or `0`, it represents `1970-01-01T00:00:00.000Z` * * 僅在輸入為數字時生效 * Only works when the input is a number */ minValidTimestamp?: number | boolean, /** * 是否將輸入時間戳視為 Unix 時間戳(秒) * Whether to use input timestamp as Unix Timestamp (seconds) * * 相當於 `dayjs.unix(1318781876.721)` 或 `dayjs(timestamp * 1000)` * Equivalent to `dayjs.unix(1318781876.721)` or `dayjs(timestamp * 1000)` * * 僅在輸入為數字時生效 * Only works when the input is a number * * @see https://day.js.org/docs/en/parse/unix-timestamp */ isUnixTimestampSeconds?: boolean, } /** * 安全解析時區日期字串 * Safely parse timezone date string * * 處理多種邊界情況,包括 UTC 偏移、浮點數字串、Unix 時間戳等 * Handle various edge cases including UTC offset, float string, Unix timestamp, etc. * * @example * tzDayjsSafeParse('2023-03-31T04:00:00.000Z') * tzDayjsSafeParse('2023-03-31T12:00:00+08:00') * tzDayjsSafeParse('2023-03-31T04:00:00.800Z') * tzDayjsSafeParse('2023-03-31T04:00:00+00:00') * // => 2023-03-31T04:00:00Z * // => 1680235200 * @example * tzDayjsSafeParse('Fri, 31 Mar 2023 04:00:00', 'GMT') * * @param {ConfigType} [dateOrMilliseconds] - 日期或毫秒時間戳 / Date or millisecond timestamp * @param {ITimezone | IOptionsTzDayjsSafeParse} [timezoneOrOptions] - 時區設定 / Timezone setting * @returns {dayjs.Dayjs} 解析後的 dayjs 物件 / Parsed dayjs object * * @see https://github.com/iamkun/dayjs/issues/2300 * @see https://github.com/iamkun/dayjs/issues/2303 * @see https://day.js.org/docs/en/timezone/timezone * @see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones */ export function tzDayjsSafeParse(dateOrMilliseconds?: ConfigType, timezoneOrOptions?: ITimezone | IOptionsTzDayjsSafeParse) { if (timezoneOrOptions === null || typeof timezoneOrOptions !== 'object') { timezoneOrOptions = { timezone: timezoneOrOptions, } as IOptionsTzDayjsSafeParse } if (typeof dateOrMilliseconds === 'number' || isFloatString(dateOrMilliseconds)) { dateOrMilliseconds = Number(dateOrMilliseconds); if (typeof timezoneOrOptions.minValidTimestamp === 'number') { dateOrMilliseconds = Math.max(dateOrMilliseconds, timezoneOrOptions.minValidTimestamp); } else if (timezoneOrOptions.minValidTimestamp) { dateOrMilliseconds = Math.max(dateOrMilliseconds, 0); } dateOrMilliseconds = (timezoneOrOptions.isUnixTimestampSeconds ? dayjs.unix : dayjs)(dateOrMilliseconds); } else if (typeof dateOrMilliseconds === 'string') { if (_isUnsafeOffsetDateString(dateOrMilliseconds)) { /** * 修復結尾為 `.000Z`、`Z`、`+00:00` 時的解析錯誤 * Fix parsing error when string ends with `.000Z`, `Z`, or `+00:00` */ dateOrMilliseconds = dayjs.utc(dateOrMilliseconds) } else if (timezoneOrOptions.timezone === 'GMT' && !_isUnsafeUTCDateString(dateOrMilliseconds)) { dateOrMilliseconds += ' GMT'; } else { dateOrMilliseconds = dayjs(dateOrMilliseconds); } } return dayjs.tz(dateOrMilliseconds ?? void 0, timezoneOrOptions.timezone ?? void 0) } /** * 秒轉毫秒 * Convert seconds to milliseconds * * @param {number} timestamp - Unix 時間戳(秒)/ Unix timestamp (seconds) * @returns {number} 毫秒時間戳 / Millisecond timestamp */ export function secondsToMilliseconds(timestamp: number) { return timestamp * 1000 } /** * 毫秒轉秒 * Convert milliseconds to seconds * * @param {number} timestamp - 毫秒時間戳 / Millisecond timestamp * @returns {number} Unix 時間戳(秒)/ Unix timestamp (seconds) */ export function millisecondsToSeconds(timestamp: number) { return timestamp / 1000 } export default tzDayjsSafeParse // @ts-ignore if (process.env.TSDX_FORMAT !== 'esm') { Object.defineProperty(tzDayjsSafeParse, "__esModule", { value: true }); Object.defineProperty(tzDayjsSafeParse, 'tzDayjsSafeParse', { value: tzDayjsSafeParse }); Object.defineProperty(tzDayjsSafeParse, 'default', { value: tzDayjsSafeParse }); Object.defineProperty(tzDayjsSafeParse, '_isUnsafeOffsetDateString', { value: _isUnsafeOffsetDateString }); Object.defineProperty(tzDayjsSafeParse, '_isUnsafeUTCDateString', { value: _isUnsafeUTCDateString }); Object.defineProperty(tzDayjsSafeParse, 'secondsToMilliseconds', { value: secondsToMilliseconds }); Object.defineProperty(tzDayjsSafeParse, 'millisecondsToSeconds', { value: millisecondsToSeconds }); }