UNPKG

@cloudcome/utils-core

Version:
356 lines (355 loc) 9.42 kB
"use strict"; const type = require("./type.cjs"); const TZ_OFFSET_MS = 60 * 1e3; class TzDate { /** * 内部时间戳 */ #timestamp; /** * 目标时区的日期对象 */ #targetDate; /** * UTC 日期对象 */ #utcDate; /** * 本地时区偏移量(分钟) */ #localTZOffset = TzDate.getOffset(); /** * 本地时区偏移量(毫秒) */ #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS; /** * 目标时区偏移量(分钟) */ #targetTzOffset = 0; /** * 目标时区偏移量(毫秒) */ #targetTzOffsetMS = 0; /** * 构造函数选项 */ #options; /** * 构造一个 TzDate 实例 * @param options - 配置选项 */ constructor(options) { this.#options = (options instanceof TzDate ? options.#options : options) || {}; const { offset, timestamp, value } = this.#options; this.#targetTzOffset = type.isNumber(offset) ? offset : this.#localTZOffset; this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS; if (Array.isArray(value) && value.length > 0) { const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value; const timestamp2 = Date.UTC( fullYear ?? 0, month ?? 0, day ?? 1, hours ?? 0, minutes ?? 0, seconds ?? 0, milliseconds ?? 0 ); this.#timestamp = timestamp2 + this.#targetTzOffsetMS; } else { this.#timestamp = timestamp || Date.now(); } this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS); this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS); } /** * 更新内部时间戳 */ #updateTimestamp() { this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS; this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS); } /** * 获取时区偏移量(分钟) * @returns 时区偏移量 */ getTimezoneOffset() { return this.#targetTzOffset; } /** * 获取时区序号 * @returns 时区序号 */ getTimezoneOrder() { return TzDate.getOrder(this.#targetTzOffset); } /** * 获取年份 * @returns 年份 */ getFullYear() { return this.#targetDate.getFullYear(); } /** * 获取月份 * @returns 月份 (0-11) */ getMonth() { return this.#targetDate.getMonth(); } /** * 获取日期 * @returns 日期 (1-31) */ getDate() { return this.#targetDate.getDate(); } /** * 获取小时 * @returns 小时 (0-23) */ getHours() { return this.#targetDate.getHours(); } /** * 获取分钟 * @returns 分钟 (0-59) */ getMinutes() { return this.#targetDate.getMinutes(); } /** * 获取秒数 * @returns 秒数 (0-59) */ getSeconds() { return this.#targetDate.getSeconds(); } /** * 获取毫秒 * @returns 毫秒 (0-999) */ getMilliseconds() { return this.#targetDate.getMilliseconds(); } /** * 设置年份 * @param year - 年份 * @param month - 月份 * @param date - 日期 * @returns 时间戳 */ setFullYear(year, month, date) { this.#targetDate.setFullYear(year); this.#updateTimestamp(); if (type.isNumber(month)) this.setMonth(month); if (type.isNumber(date)) this.setDate(date); return this.getTime(); } /** * 设置月份 * @param month - 月份 * @param date - 日期 * @returns 时间戳 */ setMonth(month, date) { this.#targetDate.setMonth(month); this.#updateTimestamp(); if (type.isNumber(date)) this.setDate(date); return this.getTime(); } /** * 设置日期 * @param date - 日期 * @returns 时间戳 */ setDate(date) { this.#targetDate.setDate(date); this.#updateTimestamp(); return this.getTime(); } /** * 设置小时 * @param hours - 小时 * @param minutes - 分钟 * @param seconds - 秒数 * @param milliseconds - 毫秒 * @returns 时间戳 */ setHours(hours, minutes, seconds, milliseconds) { this.#targetDate.setHours(hours); this.#updateTimestamp(); if (type.isNumber(minutes)) this.setMinutes(minutes); if (type.isNumber(seconds)) this.setSeconds(seconds); if (type.isNumber(milliseconds)) this.setMilliseconds(milliseconds); return this.getTime(); } /** * 设置分钟 * @param minutes - 分钟 * @param seconds - 秒数 * @param milliseconds - 毫秒 * @returns 时间戳 */ setMinutes(minutes, seconds, milliseconds) { this.#targetDate.setMinutes(minutes); this.#updateTimestamp(); if (type.isNumber(seconds)) this.setSeconds(seconds); if (type.isNumber(milliseconds)) this.setMilliseconds(milliseconds); return this.getTime(); } /** * 设置秒数 * @param seconds - 秒数 * @param milliseconds - 毫秒 * @returns 时间戳 */ setSeconds(seconds, milliseconds) { this.#targetDate.setSeconds(seconds); this.#updateTimestamp(); if (type.isNumber(milliseconds)) this.setMilliseconds(milliseconds); return this.getTime(); } /** * 设置毫秒 * @param milliseconds - 毫秒 * @returns 时间戳 */ setMilliseconds(milliseconds) { this.#targetDate.setMilliseconds(milliseconds); this.#updateTimestamp(); return this.getTime(); } /** * 获取时间戳 * @returns 时间戳 */ getTime() { return this.#timestamp; } /** * 获取星期几 * @returns 星期几 (0-6, 0表示周日) */ getDay() { return this.#targetDate.getDay(); } /** * 转换为 ISO 格式的字符串 * @returns ISO 格式的时间字符串 */ toISOString() { return dateFormat(this.#utcDate, "YYYY-MM-DDTHH:mm:ss.SSSZ"); } /** * 创建一个 TzDate 对象 * @param td - 需要转换的日期对象 * @param offset - 目标时区分钟偏移量,默认为当前时区 * @returns 返回一个 TzDate 对象 * @example * ```js * const tzDate = TzDate.from(new TzDate()); * ``` */ static from(td, offset = TzDate.getOffset()) { return new TzDate({ offset, timestamp: td.getTime() }); } /** * 获取时区序号 * @param offset - 默认使用当前时区分钟偏移量 * @returns 时区序号 */ static getOrder(offset = TzDate.getOffset()) { return offset / -60; } /** * 获取时区分钟偏移量 * @param gmtOrder - 默认使用当前时区序号 * @returns 时区分钟偏移量 */ static getOffset(gmtOrder) { return type.isNumber(gmtOrder) ? gmtOrder * -60 : (/* @__PURE__ */ new Date()).getTimezoneOffset(); } } function isValidDate(unknown) { return unknown instanceof Date && !Number.isNaN(unknown.getTime()) || unknown instanceof TzDate && !Number.isNaN(unknown.getTime()); } function _guessDateSeparator(value) { if (!type.isString(value)) return; const value2 = value.replace(/-/g, "/"); return new Date(value2); } function _guessDateTimezone(value) { if (!type.isString(value)) return; const re = /([+-])(\d\d)(\d\d)$/; const matches = re.exec(value); if (!matches) return; const value2 = value.replace(re, "Z"); const d = new Date(value2); if (!isValidDate(d)) return; const [, flag, hours, minutes] = matches; const hours2 = Number.parseInt(hours, 10); const minutes2 = Number.parseInt(minutes, 10); const offset = (a, b) => flag === "+" ? a - b : a + b; d.setHours(offset(d.getHours(), hours2)); d.setMinutes(offset(d.getMinutes(), minutes2)); return d; } function dateParse(dateValue) { const d1 = type.isDate(dateValue) ? new Date(dateValue) : dateValue instanceof TzDate ? new TzDate(dateValue) : new Date(dateValue); if (isValidDate(d1)) return d1; const d2 = _guessDateSeparator(dateValue); if (isValidDate(d2)) return d2; const d3 = _guessDateTimezone(dateValue); if (isValidDate(d3)) return d3; throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`); } function _pad(num, len = 2) { return `${num}`.padStart(len, "0"); } const rules = [ [/Y{4}/gi, (date) => date.getFullYear()], [/Y{2}/gi, (date) => date.getFullYear() % 100], [/M{2}/g, (date) => _pad(date.getMonth() + 1)], [/M{1}/g, (date) => date.getMonth() + 1], [/D{2}/gi, (date) => _pad(date.getDate())], [/D{1}/gi, (date) => date.getDate()], [/H{2}/g, (date) => _pad(date.getHours())], [/H{1}/g, (date) => date.getHours()], [ /h{2}/g, (date) => { const h = date.getHours(); return _pad(h > 12 ? h - 12 : h); } ], [ /h{1}/g, (date) => { const h = date.getHours(); return h > 12 ? h - 12 : h; } ], [/m{2}/g, (date) => _pad(date.getMinutes())], [/m{1}/g, (date) => date.getMinutes()], [/s{2}/g, (date) => _pad(date.getSeconds())], [/s{1}/g, (date) => date.getSeconds()], [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)], [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)], [/S{1}/g, (date) => date.getMilliseconds()] ]; function dateFormat(dateValue, format = "YYYY-MM-DD HH:mm:ss") { const date = dateParse(dateValue); let result = format; for (const rule of rules) { result = result.replace(rule[0], String(rule[1](date))); } return result; } exports.TzDate = TzDate; exports.dateFormat = dateFormat; exports.dateParse = dateParse; exports.isValidDate = isValidDate; //# sourceMappingURL=core.cjs.map