@cloudcome/utils-core
Version:
cloudcome core utils
356 lines (355 loc) • 9.42 kB
JavaScript
"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