@cloudcome/utils-core 1.15.7 → 1.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/array.cjs CHANGED
@@ -71,59 +71,80 @@ function arrayMove(array, from, to) {
71
71
  array2.splice(to, 0, item);
72
72
  return array2;
73
73
  }
74
- function arrayDiff(refArray, curArray) {
74
+ function arrayDiff(refArray, curArray, options) {
75
+ const { getItemKey = (item) => item } = options || {};
76
+ const toKeyIndexes = (map, item) => {
77
+ const key = getItemKey(item);
78
+ return {
79
+ key,
80
+ indexes: map.get(key) || []
81
+ };
82
+ };
75
83
  const buildMap = (arr) => {
76
84
  const map = /* @__PURE__ */ new Map();
77
85
  arr.forEach((item, index) => {
78
- const indexes = map.get(item) || [];
86
+ const { key, indexes } = toKeyIndexes(map, item);
79
87
  indexes.push(index);
80
- map.set(item, indexes);
88
+ map.set(key, indexes);
81
89
  });
82
90
  return map;
83
91
  };
84
- const map1 = buildMap(refArray);
85
- const map2 = buildMap(curArray);
86
- const deletes = /* @__PURE__ */ new Set();
87
- const adds = /* @__PURE__ */ new Set();
88
- const equals = /* @__PURE__ */ new Set();
89
- for (const key of map1.keys()) {
90
- if (map2.has(key)) {
91
- equals.add(key);
92
+ const toIndexesArr = (arr, indexes) => {
93
+ return indexes.map((index) => arr[index]);
94
+ };
95
+ const refMap = buildMap(refArray);
96
+ const curMap = buildMap(curArray);
97
+ const deleteSet = /* @__PURE__ */ new Set();
98
+ const addSet = /* @__PURE__ */ new Set();
99
+ const equalSet = /* @__PURE__ */ new Set();
100
+ for (const key of refMap.keys()) {
101
+ if (curMap.has(key)) {
102
+ equalSet.add(key);
92
103
  } else {
93
- deletes.add(key);
104
+ deleteSet.add(key);
94
105
  }
95
106
  }
96
- for (const key of map2.keys()) {
97
- if (!map1.has(key)) {
98
- adds.add(key);
107
+ for (const key of curMap.keys()) {
108
+ if (!refMap.has(key)) {
109
+ addSet.add(key);
99
110
  }
100
111
  }
101
112
  return {
102
- deletes: [...deletes].map((it) => ({
103
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
104
- refIndexes: map1.get(it),
105
- refValue: it
106
- })),
107
- adds: [...adds].map((it) => ({
108
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
109
- curIndexes: map2.get(it),
110
- curValue: it
111
- })),
112
- equals: [...equals].map((it) => ({
113
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
114
- refIndexes: map1.get(it),
115
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
116
- curIndexes: map2.get(it),
117
- refValue: it,
118
- curValue: it
119
- }))
113
+ deletes: [...deleteSet].map((key) => {
114
+ const indexes = refMap.get(key) || [];
115
+ return {
116
+ refIndexes: indexes,
117
+ refValues: toIndexesArr(refArray, indexes)
118
+ };
119
+ }),
120
+ adds: [...addSet].map((key) => {
121
+ const indexes = curMap.get(key) || [];
122
+ return {
123
+ curIndexes: indexes,
124
+ curValues: toIndexesArr(curArray, indexes)
125
+ };
126
+ }),
127
+ equals: [...equalSet].map((key) => {
128
+ const refIndexes = refMap.get(key) || [];
129
+ const curIndexes = curMap.get(key) || [];
130
+ return {
131
+ refIndexes,
132
+ curIndexes,
133
+ refValues: toIndexesArr(refArray, refIndexes),
134
+ curValues: toIndexesArr(curArray, curIndexes)
135
+ };
136
+ })
120
137
  };
121
138
  }
139
+ function arrayRemove(array, indexes) {
140
+ return array.filter((item, index) => !indexes.includes(index));
141
+ }
122
142
  exports.arrayDiff = arrayDiff;
123
143
  exports.arrayEach = arrayEach;
124
144
  exports.arrayEachAsync = arrayEachAsync;
125
145
  exports.arrayMove = arrayMove;
126
146
  exports.arrayOmit = arrayOmit;
127
147
  exports.arrayPick = arrayPick;
148
+ exports.arrayRemove = arrayRemove;
128
149
  exports.isArrayLike = isArrayLike;
129
150
  //# sourceMappingURL=array.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"array.cjs","sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T}\n */\n refValue: T;\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T}\n */\n curValue: T;\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T}\n */\n refValue: T;\n /**\n * 当前数组中的元素值\n * @type {T}\n */\n curValue: T;\n }[];\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[]): ArrayDiffs<T> {\n const buildMap = (arr: T[]) => {\n const map = new Map<T, number[]>();\n\n arr.forEach((item, index) => {\n const indexes = map.get(item) || [];\n indexes.push(index);\n map.set(item, indexes);\n });\n\n return map;\n };\n const map1 = buildMap(refArray);\n const map2 = buildMap(curArray);\n const deletes = new Set<T>();\n const adds = new Set<T>();\n const equals = new Set<T>();\n\n for (const key of map1.keys()) {\n if (map2.has(key)) {\n equals.add(key);\n } else {\n deletes.add(key);\n }\n }\n\n for (const key of map2.keys()) {\n if (!map1.has(key)) {\n adds.add(key);\n }\n }\n\n return {\n deletes: [...deletes].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n refIndexes: map1.get(it)!,\n refValue: it,\n })),\n\n adds: [...adds].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n curIndexes: map2.get(it)!,\n curValue: it,\n })),\n\n equals: [...equals].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n refIndexes: map1.get(it)!,\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n curIndexes: map2.get(it)!,\n refValue: it,\n curValue: it,\n })),\n };\n}\n"],"names":["isArray","isObject"],"mappings":"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"}
1
+ {"version":3,"file":"array.cjs","sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((item, index) => !indexes.includes(index));\n}\n"],"names":["isArray","isObject"],"mappings":"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"}
package/dist/array.d.ts CHANGED
@@ -115,9 +115,9 @@ export type ArrayDiffs<T> = {
115
115
  refIndexes: number[];
116
116
  /**
117
117
  * 被删除的元素值
118
- * @type {T}
118
+ * @type {T[]}
119
119
  */
120
- refValue: T;
120
+ refValues: T[];
121
121
  }[];
122
122
  /**
123
123
  * 新增的元素列表
@@ -133,9 +133,9 @@ export type ArrayDiffs<T> = {
133
133
  curIndexes: number[];
134
134
  /**
135
135
  * 新增的元素值
136
- * @type {T}
136
+ * @type {T[]}
137
137
  */
138
- curValue: T;
138
+ curValues: T[];
139
139
  }[];
140
140
  /**
141
141
  * 相同的元素列表
@@ -158,14 +158,32 @@ export type ArrayDiffs<T> = {
158
158
  curIndexes: number[];
159
159
  /**
160
160
  * 参考数组中的元素值
161
- * @type {T}
161
+ * @type {T[]}
162
162
  */
163
- refValue: T;
163
+ refValues: T[];
164
164
  /**
165
165
  * 当前数组中的元素值
166
- * @type {T}
166
+ * @type {T[]}
167
167
  */
168
- curValue: T;
168
+ curValues: T[];
169
169
  }[];
170
170
  };
171
- export declare function arrayDiff<T>(refArray: T[], curArray: T[]): ArrayDiffs<T>;
171
+ export type ArrayDiffOptions<T> = {
172
+ getItemKey: (item: T) => unknown;
173
+ };
174
+ export declare function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T>;
175
+ /**
176
+ * 从数组中移除指定索引的元素
177
+ * @template T - 数组元素的类型
178
+ * @param {T[]} array - 原始数组
179
+ * @param {number[]} indexes - 要移除的元素索引数组
180
+ * @returns {T[]} 移除指定索引元素后的新数组
181
+ *
182
+ * @example
183
+ * ```typescript
184
+ * const arr = [1, 2, 3, 4, 5];
185
+ * const newArr = arrayRemove(arr, [1, 3]);
186
+ * // 返回结果: [1, 3, 5]
187
+ * ```
188
+ */
189
+ export declare function arrayRemove<T>(array: T[], indexes: number[]): T[];
package/dist/array.mjs CHANGED
@@ -69,54 +69,74 @@ function arrayMove(array, from, to) {
69
69
  array2.splice(to, 0, item);
70
70
  return array2;
71
71
  }
72
- function arrayDiff(refArray, curArray) {
72
+ function arrayDiff(refArray, curArray, options) {
73
+ const { getItemKey = (item) => item } = options || {};
74
+ const toKeyIndexes = (map, item) => {
75
+ const key = getItemKey(item);
76
+ return {
77
+ key,
78
+ indexes: map.get(key) || []
79
+ };
80
+ };
73
81
  const buildMap = (arr) => {
74
82
  const map = /* @__PURE__ */ new Map();
75
83
  arr.forEach((item, index) => {
76
- const indexes = map.get(item) || [];
84
+ const { key, indexes } = toKeyIndexes(map, item);
77
85
  indexes.push(index);
78
- map.set(item, indexes);
86
+ map.set(key, indexes);
79
87
  });
80
88
  return map;
81
89
  };
82
- const map1 = buildMap(refArray);
83
- const map2 = buildMap(curArray);
84
- const deletes = /* @__PURE__ */ new Set();
85
- const adds = /* @__PURE__ */ new Set();
86
- const equals = /* @__PURE__ */ new Set();
87
- for (const key of map1.keys()) {
88
- if (map2.has(key)) {
89
- equals.add(key);
90
+ const toIndexesArr = (arr, indexes) => {
91
+ return indexes.map((index) => arr[index]);
92
+ };
93
+ const refMap = buildMap(refArray);
94
+ const curMap = buildMap(curArray);
95
+ const deleteSet = /* @__PURE__ */ new Set();
96
+ const addSet = /* @__PURE__ */ new Set();
97
+ const equalSet = /* @__PURE__ */ new Set();
98
+ for (const key of refMap.keys()) {
99
+ if (curMap.has(key)) {
100
+ equalSet.add(key);
90
101
  } else {
91
- deletes.add(key);
102
+ deleteSet.add(key);
92
103
  }
93
104
  }
94
- for (const key of map2.keys()) {
95
- if (!map1.has(key)) {
96
- adds.add(key);
105
+ for (const key of curMap.keys()) {
106
+ if (!refMap.has(key)) {
107
+ addSet.add(key);
97
108
  }
98
109
  }
99
110
  return {
100
- deletes: [...deletes].map((it) => ({
101
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
102
- refIndexes: map1.get(it),
103
- refValue: it
104
- })),
105
- adds: [...adds].map((it) => ({
106
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
107
- curIndexes: map2.get(it),
108
- curValue: it
109
- })),
110
- equals: [...equals].map((it) => ({
111
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
112
- refIndexes: map1.get(it),
113
- // biome-ignore lint/style/noNonNullAssertion: <explanation>
114
- curIndexes: map2.get(it),
115
- refValue: it,
116
- curValue: it
117
- }))
111
+ deletes: [...deleteSet].map((key) => {
112
+ const indexes = refMap.get(key) || [];
113
+ return {
114
+ refIndexes: indexes,
115
+ refValues: toIndexesArr(refArray, indexes)
116
+ };
117
+ }),
118
+ adds: [...addSet].map((key) => {
119
+ const indexes = curMap.get(key) || [];
120
+ return {
121
+ curIndexes: indexes,
122
+ curValues: toIndexesArr(curArray, indexes)
123
+ };
124
+ }),
125
+ equals: [...equalSet].map((key) => {
126
+ const refIndexes = refMap.get(key) || [];
127
+ const curIndexes = curMap.get(key) || [];
128
+ return {
129
+ refIndexes,
130
+ curIndexes,
131
+ refValues: toIndexesArr(refArray, refIndexes),
132
+ curValues: toIndexesArr(curArray, curIndexes)
133
+ };
134
+ })
118
135
  };
119
136
  }
137
+ function arrayRemove(array, indexes) {
138
+ return array.filter((item, index) => !indexes.includes(index));
139
+ }
120
140
  export {
121
141
  arrayDiff,
122
142
  arrayEach,
@@ -124,6 +144,7 @@ export {
124
144
  arrayMove,
125
145
  arrayOmit,
126
146
  arrayPick,
147
+ arrayRemove,
127
148
  isArrayLike
128
149
  };
129
150
  //# sourceMappingURL=array.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"array.mjs","sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T}\n */\n refValue: T;\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T}\n */\n curValue: T;\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T}\n */\n refValue: T;\n /**\n * 当前数组中的元素值\n * @type {T}\n */\n curValue: T;\n }[];\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[]): ArrayDiffs<T> {\n const buildMap = (arr: T[]) => {\n const map = new Map<T, number[]>();\n\n arr.forEach((item, index) => {\n const indexes = map.get(item) || [];\n indexes.push(index);\n map.set(item, indexes);\n });\n\n return map;\n };\n const map1 = buildMap(refArray);\n const map2 = buildMap(curArray);\n const deletes = new Set<T>();\n const adds = new Set<T>();\n const equals = new Set<T>();\n\n for (const key of map1.keys()) {\n if (map2.has(key)) {\n equals.add(key);\n } else {\n deletes.add(key);\n }\n }\n\n for (const key of map2.keys()) {\n if (!map1.has(key)) {\n adds.add(key);\n }\n }\n\n return {\n deletes: [...deletes].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n refIndexes: map1.get(it)!,\n refValue: it,\n })),\n\n adds: [...adds].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n curIndexes: map2.get(it)!,\n curValue: it,\n })),\n\n equals: [...equals].map((it) => ({\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n refIndexes: map1.get(it)!,\n // biome-ignore lint/style/noNonNullAssertion: <explanation>\n curIndexes: map2.get(it)!,\n refValue: it,\n curValue: it,\n })),\n };\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"array.mjs","sources":["../src/array.ts"],"sourcesContent":["import { isArray, isObject } from './type';\nimport type { MaybePromise } from './types';\n\n/**\n * 检查给定的值是否为类数组对象。\n *\n * 类数组对象是指具有 `length` 属性且 `length` 属性为非负数的对象。\n *\n * @param unknown - 要检查的值。\n * @returns 如果值是类数组对象,则返回 `true`,否则返回 `false`。\n */\nexport function isArrayLike(unknown: unknown) {\n if (isArray(unknown)) return true;\n\n if (isObject(unknown)) {\n const arrayLike = unknown as { length: unknown };\n return typeof arrayLike.length === 'number' && arrayLike.length >= 0;\n }\n\n return false;\n}\n\n/**\n * 从数组中选择指定索引的元素。\n *\n * @param array - 要从中选择元素的数组。\n * @param indexes - 要选择的元素的索引数组。\n * @returns 包含指定索引元素的新数组。\n */\nexport function arrayPick<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return false;\n indexes2.splice(index, 1);\n return true;\n });\n}\n\n/**\n * 从数组中排除指定索引的元素。\n *\n * @param array - 要从中排除元素的数组。\n * @param indexes - 要排除的元素的索引数组。\n * @returns 包含排除指定索引元素后的新数组。\n */\nexport function arrayOmit<T>(array: T[], indexes: number[]) {\n const indexes2 = [...indexes];\n return array.filter((_, i) => {\n const index = indexes2.indexOf(i);\n if (index === -1) return true;\n indexes2.splice(index, 1);\n return false;\n });\n}\n\n/**\n * 遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * arrayEach(arr, (item, index) => {\n * console.log(item, index);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport function arrayEach<T>(array: T[], iterator: (item: T, index: number) => false | unknown, reverse = false) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if (iterator(_array[i], i) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 异步遍历数组中的每个元素,并对每个元素执行提供的回调函数。\n *\n * @param array - 要遍历的数组。\n * @param iterator - 对每个元素执行的异步回调函数。如果回调函数返回 `false`,则提前终止遍历。\n * @param reverse - 是否以相反的顺序遍历数组。默认为 `false`。\n * @returns 无返回值。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3];\n * await arrayEachAsync(arr, async (item, index) => {\n * await someAsyncOperation(item);\n * if (index === 1) return false; // 提前终止遍历\n * });\n * ```\n */\nexport async function arrayEachAsync<T>(\n array: T[],\n iterator: (item: T, index: number) => MaybePromise<false | unknown>,\n reverse = false,\n) {\n const _array = [...array];\n const length = array.length;\n\n if (reverse) {\n for (let i = length - 1; i >= 0; i--) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n } else {\n for (let i = 0; i < length; i++) {\n if ((await iterator(_array[i], i)) === false) {\n break;\n }\n }\n }\n}\n\n/**\n * 将数组中的元素移动到指定位置。\n *\n * @param array - 要移动元素的数组。\n * @param from - 要移动的元素的起始位置。\n * @param to - 要移动的元素的目标位置。\n * @returns 新的数组,其中包含移动后的元素。\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayMove(arr, 1, 3);\n * // 返回 [1, 3, 4, 2, 5]\n * ```\n */\nexport function arrayMove<T>(array: T[], from: number, to: number) {\n const array2 = [...array];\n\n if (from < 0 || from >= array2.length || to < 0 || to >= array2.length) {\n return array2;\n }\n\n const item = array2[from];\n\n array2.splice(from, 1);\n array2.splice(to, 0, item);\n\n return array2;\n}\n\n/**\n * 比较两个数组的差异,返回包含删除、新增和相同元素信息的对象\n *\n * @template T - 数组元素的类型\n * @param {T[]} refArray - 参考数组(原始数组)\n * @param {T[]} curArray - 当前数组(比较数组)\n * @returns {ArrayDiffs<T>} 包含差异信息的对象\n *\n * @example\n * ```typescript\n * const ref = [1, 2, 3];\n * const cur = [2, 3, 4];\n * const diff = arrayDiff(ref, cur);\n * // 返回结果:\n * // {\n * // deletes: [{refIndexes: [0], refValue: 1}],\n * // adds: [{curIndexes: [2], curValue: 4}],\n * // equals: [\n * // {refIndexes: [1], curIndexes: [0], refValue: 2, curValue: 2},\n * // {refIndexes: [2], curIndexes: [1], refValue: 3, curValue: 3}\n * // ]\n * // }\n * ```\n */\nexport type ArrayDiffs<T> = {\n /**\n * 被删除的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {T} refValue - 被删除的元素值\n */\n deletes: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 被删除的元素值\n * @type {T[]}\n */\n refValues: T[];\n }[];\n\n /**\n * 新增的元素列表\n * @type {Array}\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} curValue - 新增的元素值\n */\n adds: {\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 新增的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n\n /**\n * 相同的元素列表\n * @type {Array}\n * @property {number[]} refIndexes - 元素在参考数组中的所有索引位置\n * @property {number[]} curIndexes - 元素在当前数组中的所有索引位置\n * @property {T} refValue - 参考数组中的元素值\n * @property {T} curValue - 当前数组中的元素值\n */\n equals: {\n /**\n * 元素在参考数组中的所有索引位置\n * @type {number[]}\n */\n refIndexes: number[];\n /**\n * 元素在当前数组中的所有索引位置\n * @type {number[]}\n */\n curIndexes: number[];\n /**\n * 参考数组中的元素值\n * @type {T[]}\n */\n refValues: T[];\n /**\n * 当前数组中的元素值\n * @type {T[]}\n */\n curValues: T[];\n }[];\n};\n\nexport type ArrayDiffOptions<T> = {\n getItemKey: (item: T) => unknown;\n};\n\nexport function arrayDiff<T>(refArray: T[], curArray: T[], options?: ArrayDiffOptions<T>): ArrayDiffs<T> {\n const { getItemKey = (item: T) => item } = options || {};\n\n // biome-ignore lint/suspicious/noExplicitAny: <explanation>\n type Key = any;\n\n const toKeyIndexes = (map: Map<Key, number[]>, item: T) => {\n const key = getItemKey(item);\n return {\n key,\n indexes: map.get(key) || [],\n };\n };\n\n const buildMap = (arr: T[]) => {\n const map = new Map<Key, number[]>();\n\n arr.forEach((item, index) => {\n const { key, indexes } = toKeyIndexes(map, item);\n indexes.push(index);\n map.set(key, indexes);\n });\n\n return map;\n };\n\n const toIndexesArr = (arr: T[], indexes: number[]) => {\n return indexes.map((index) => arr[index]);\n };\n\n const refMap = buildMap(refArray);\n const curMap = buildMap(curArray);\n const deleteSet = new Set<Key>();\n const addSet = new Set<Key>();\n const equalSet = new Set<Key>();\n\n for (const key of refMap.keys()) {\n if (curMap.has(key)) {\n equalSet.add(key);\n } else {\n deleteSet.add(key);\n }\n }\n\n for (const key of curMap.keys()) {\n if (!refMap.has(key)) {\n addSet.add(key);\n }\n }\n\n return {\n deletes: [...deleteSet].map((key) => {\n const indexes = refMap.get(key) || [];\n return {\n refIndexes: indexes,\n refValues: toIndexesArr(refArray, indexes),\n };\n }),\n\n adds: [...addSet].map((key) => {\n const indexes = curMap.get(key) || [];\n return {\n curIndexes: indexes,\n curValues: toIndexesArr(curArray, indexes),\n };\n }),\n\n equals: [...equalSet].map((key) => {\n const refIndexes = refMap.get(key) || [];\n const curIndexes = curMap.get(key) || [];\n return {\n refIndexes,\n curIndexes,\n refValues: toIndexesArr(refArray, refIndexes),\n curValues: toIndexesArr(curArray, curIndexes),\n };\n }),\n };\n}\n\n/**\n * 从数组中移除指定索引的元素\n * @template T - 数组元素的类型\n * @param {T[]} array - 原始数组\n * @param {number[]} indexes - 要移除的元素索引数组\n * @returns {T[]} 移除指定索引元素后的新数组\n *\n * @example\n * ```typescript\n * const arr = [1, 2, 3, 4, 5];\n * const newArr = arrayRemove(arr, [1, 3]);\n * // 返回结果: [1, 3, 5]\n * ```\n */\nexport function arrayRemove<T>(array: T[], indexes: number[]) {\n return array.filter((item, index) => !indexes.includes(index));\n}\n"],"names":[],"mappings":"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"}
package/dist/core.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  const type = require("./type.cjs");
3
- const TZ_OFFSET_MS = 60 * 1e3;
4
- class TzDate {
3
+ const TIMEZONE_OFFSET_MS = 60 * 1e3;
4
+ class TimezoneDate {
5
5
  /**
6
6
  * 内部时间戳
7
7
  */
@@ -17,35 +17,35 @@ class TzDate {
17
17
  /**
18
18
  * 本地时区偏移量(分钟)
19
19
  */
20
- #localTZOffset = TzDate.getOffset();
20
+ #localTimezoneOffset = TimezoneDate.getTimezoneOffset();
21
21
  /**
22
22
  * 本地时区偏移量(毫秒)
23
23
  */
24
- #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;
24
+ #localTimezoneOffsetMS = this.#localTimezoneOffset * TIMEZONE_OFFSET_MS;
25
25
  /**
26
26
  * 目标时区偏移量(分钟)
27
27
  */
28
- #targetTzOffset = 0;
28
+ #targetTimezoneOffset = 0;
29
29
  /**
30
30
  * 目标时区偏移量(毫秒)
31
31
  */
32
- #targetTzOffsetMS = 0;
32
+ #targetTimezoneOffsetMS = 0;
33
33
  /**
34
34
  * 构造函数选项
35
35
  */
36
36
  #options;
37
37
  /**
38
- * 构造一个 TzDate 实例
38
+ * 构造一个 TimezoneDate 实例
39
39
  * @param options - 配置选项
40
40
  */
41
41
  constructor(options) {
42
- this.#options = (options instanceof TzDate ? {
42
+ this.#options = (options instanceof TimezoneDate ? {
43
43
  timestamp: options.getTime(),
44
- offset: options.getTimezoneOffset()
44
+ utcOffset: options.getUTCOffset()
45
45
  } : options) || {};
46
- const { offset, timestamp, value } = this.#options;
47
- this.#targetTzOffset = type.isNumber(offset) ? offset : this.#localTZOffset;
48
- this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;
46
+ const { utcOffset, timestamp, value } = this.#options;
47
+ this.#targetTimezoneOffset = type.isNumber(utcOffset) ? TimezoneDate.getTimezoneOffset(utcOffset) : this.#localTimezoneOffset;
48
+ this.#targetTimezoneOffsetMS = this.#targetTimezoneOffset * TIMEZONE_OFFSET_MS;
49
49
  if (Array.isArray(value) && value.length > 0) {
50
50
  const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;
51
51
  const timestamp2 = Date.UTC(
@@ -57,33 +57,33 @@ class TzDate {
57
57
  seconds ?? 0,
58
58
  milliseconds ?? 0
59
59
  );
60
- this.#timestamp = timestamp2 + this.#targetTzOffsetMS;
60
+ this.#timestamp = timestamp2 + this.#targetTimezoneOffsetMS;
61
61
  } else {
62
62
  this.#timestamp = timestamp || Date.now();
63
63
  }
64
- this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);
65
- this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
64
+ this.#targetDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS - this.#targetTimezoneOffsetMS);
65
+ this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);
66
66
  }
67
67
  /**
68
68
  * 更新内部时间戳
69
69
  */
70
70
  #updateTimestamp() {
71
- this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;
72
- this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
71
+ this.#timestamp = this.#targetDate.getTime() + this.#targetTimezoneOffsetMS - this.#localTimezoneOffsetMS;
72
+ this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);
73
73
  }
74
74
  /**
75
75
  * 获取时区偏移量(分钟)
76
76
  * @returns 时区偏移量
77
77
  */
78
78
  getTimezoneOffset() {
79
- return this.#targetTzOffset;
79
+ return this.#targetTimezoneOffset;
80
80
  }
81
81
  /**
82
- * 获取时区序号
82
+ * 获取时区偏移量(UTC)
83
83
  * @returns 时区序号
84
84
  */
85
- getTimezoneOrder() {
86
- return TzDate.getOrder(this.#targetTzOffset);
85
+ getUTCOffset() {
86
+ return TimezoneDate.getUTCOffset(this.#targetTimezoneOffset);
87
87
  }
88
88
  /**
89
89
  * 获取年份
@@ -244,40 +244,44 @@ class TzDate {
244
244
  return dateFormat(this.#utcDate, "YYYY-MM-DDTHH:mm:ss.SSSZ");
245
245
  }
246
246
  /**
247
- * 创建一个 TzDate 对象
247
+ * 转换为指定时区的 TimezoneDate 对象
248
248
  * @param td - 需要转换的日期对象
249
249
  * @param offset - 目标时区分钟偏移量,默认为当前时区
250
- * @returns 返回一个 TzDate 对象
250
+ * @returns 返回一个 TimezoneDate 对象
251
251
  * @example
252
252
  * ```js
253
- * const tzDate = TzDate.from(new TzDate());
253
+ * // 转换为 UTC 时间
254
+ * const utc0Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 0);
255
+ *
256
+ * // 转换为东八区时间
257
+ * const utc8Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 8);
254
258
  * ```
255
259
  */
256
- static from(td, offset = TzDate.getOffset()) {
257
- return new TzDate({
258
- offset,
260
+ static changeUtcOffset(td, utcOffset) {
261
+ return new TimezoneDate({
262
+ utcOffset,
259
263
  timestamp: td.getTime()
260
264
  });
261
265
  }
262
266
  /**
263
- * 获取时区序号
264
- * @param offset - 默认使用当前时区分钟偏移量
265
- * @returns 时区序号
267
+ * 获取时区分钟偏移量
268
+ * @param utcOffset - 默认使用当前时区
269
+ * @returns 时区分钟偏移量
266
270
  */
267
- static getOrder(offset = TzDate.getOffset()) {
268
- return offset / -60;
271
+ static getTimezoneOffset(utcOffset) {
272
+ return type.isNumber(utcOffset) ? utcOffset * -60 : (/* @__PURE__ */ new Date()).getTimezoneOffset();
269
273
  }
270
274
  /**
271
- * 获取时区分钟偏移量
272
- * @param gmtOrder - 默认使用当前时区序号
273
- * @returns 时区分钟偏移量
275
+ * 获取时区序号
276
+ * @param timezoneOffset - 默认使用当前时区分钟偏移量
277
+ * @returns 时区序号
274
278
  */
275
- static getOffset(gmtOrder) {
276
- return type.isNumber(gmtOrder) ? gmtOrder * -60 : (/* @__PURE__ */ new Date()).getTimezoneOffset();
279
+ static getUTCOffset(timezoneOffset = TimezoneDate.getTimezoneOffset()) {
280
+ return timezoneOffset / -60;
277
281
  }
278
282
  }
279
283
  function isValidDate(unknown) {
280
- return unknown instanceof Date && !Number.isNaN(unknown.getTime()) || unknown instanceof TzDate && !Number.isNaN(unknown.getTime());
284
+ return unknown instanceof Date && !Number.isNaN(unknown.getTime()) || unknown instanceof TimezoneDate && !Number.isNaN(unknown.getTime());
281
285
  }
282
286
  function _guessDateSeparator(value) {
283
287
  if (!type.isString(value)) return;
@@ -301,7 +305,7 @@ function _guessDateTimezone(value) {
301
305
  return d;
302
306
  }
303
307
  function dateParse(dateValue) {
304
- const d1 = type.isDate(dateValue) ? new Date(dateValue) : dateValue instanceof TzDate ? new TzDate(dateValue) : new Date(dateValue);
308
+ const d1 = type.isDate(dateValue) ? new Date(dateValue) : dateValue instanceof TimezoneDate ? new TimezoneDate(dateValue) : new Date(dateValue);
305
309
  if (isValidDate(d1)) return d1;
306
310
  const d2 = _guessDateSeparator(dateValue);
307
311
  if (isValidDate(d2)) return d2;
@@ -351,7 +355,7 @@ function dateFormat(dateValue, format = "YYYY-MM-DD HH:mm:ss") {
351
355
  }
352
356
  return result;
353
357
  }
354
- exports.TzDate = TzDate;
358
+ exports.TimezoneDate = TimezoneDate;
355
359
  exports.dateFormat = dateFormat;
356
360
  exports.dateParse = dateParse;
357
361
  exports.isValidDate = isValidDate;
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.cjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\n/**\n * 时区偏移量毫秒常量(1分钟 = 60 * 1000 毫秒)\n */\nconst TZ_OFFSET_MS = 60 * 1000;\n\n/**\n * 时区日期类,用于处理不同时区的日期时间\n */\nexport class TzDate {\n /**\n * 内部时间戳\n */\n #timestamp: number;\n\n /**\n * 目标时区的日期对象\n */\n #targetDate: Date;\n\n /**\n * UTC 日期对象\n */\n #utcDate: Date;\n\n /**\n * 本地时区偏移量(分钟)\n */\n #localTZOffset = TzDate.getOffset();\n\n /**\n * 本地时区偏移量(毫秒)\n */\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n /**\n * 目标时区偏移量(分钟)\n */\n #targetTzOffset = 0;\n\n /**\n * 目标时区偏移量(毫秒)\n */\n #targetTzOffsetMS = 0;\n\n /**\n * 构造函数选项\n */\n #options: TzDateOptions;\n\n /**\n * 构造一个 TzDate 实例\n * @param options - 配置选项\n */\n constructor(options?: TzDateOptions | TzDate) {\n this.#options =\n (options instanceof TzDate\n ? {\n timestamp: options.getTime(),\n offset: options.getTimezoneOffset(),\n }\n : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n /**\n * 更新内部时间戳\n */\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n /**\n * 获取时区偏移量(分钟)\n * @returns 时区偏移量\n */\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n /**\n * 获取时区序号\n * @returns 时区序号\n */\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n /**\n * 获取年份\n * @returns 年份\n */\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n /**\n * 获取月份\n * @returns 月份 (0-11)\n */\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n /**\n * 获取日期\n * @returns 日期 (1-31)\n */\n getDate() {\n return this.#targetDate.getDate();\n }\n\n /**\n * 获取小时\n * @returns 小时 (0-23)\n */\n getHours() {\n return this.#targetDate.getHours();\n }\n\n /**\n * 获取分钟\n * @returns 分钟 (0-59)\n */\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n /**\n * 获取秒数\n * @returns 秒数 (0-59)\n */\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n /**\n * 获取毫秒\n * @returns 毫秒 (0-999)\n */\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n /**\n * 设置年份\n * @param year - 年份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置月份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置日期\n * @param date - 日期\n * @returns 时间戳\n */\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 设置小时\n * @param hours - 小时\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置分钟\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置秒数\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置毫秒\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 获取时间戳\n * @returns 时间戳\n */\n getTime() {\n return this.#timestamp;\n }\n\n /**\n * 获取星期几\n * @returns 星期几 (0-6, 0表示周日)\n */\n getDay() {\n return this.#targetDate.getDay();\n }\n\n /**\n * 转换为 ISO 格式的字符串\n * @returns ISO 格式的时间字符串\n */\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n * @returns 时区序号\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n * @returns 时区分钟偏移量\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TzDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["isNumber","timestamp","isString","isDate"],"mappings":"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"}
1
+ {"version":3,"file":"core.cjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TimezoneDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * UTC 时区,支持负数和小数,例如:\n * - 8 表示 UTC+8\n * - -12 表示 UTC-12\n * - 0 表示 UTC 时间\n * - 12.5 表示 UTC+12:30\n */\n utcOffset?: number;\n};\n\n/**\n * 时区偏移量毫秒常量(1分钟 = 60 * 1000 毫秒)\n */\nconst TIMEZONE_OFFSET_MS = 60 * 1000;\n\n/**\n * 时区日期类,用于处理不同时区的日期时间\n */\nexport class TimezoneDate {\n /**\n * 内部时间戳\n */\n #timestamp: number;\n\n /**\n * 目标时区的日期对象\n */\n #targetDate: Date;\n\n /**\n * UTC 日期对象\n */\n #utcDate: Date;\n\n /**\n * 本地时区偏移量(分钟)\n */\n #localTimezoneOffset = TimezoneDate.getTimezoneOffset();\n\n /**\n * 本地时区偏移量(毫秒)\n */\n #localTimezoneOffsetMS = this.#localTimezoneOffset * TIMEZONE_OFFSET_MS;\n\n /**\n * 目标时区偏移量(分钟)\n */\n #targetTimezoneOffset = 0;\n\n /**\n * 目标时区偏移量(毫秒)\n */\n #targetTimezoneOffsetMS = 0;\n\n /**\n * 构造函数选项\n */\n #options: TimezoneDateOptions;\n\n /**\n * 构造一个 TimezoneDate 实例\n * @param options - 配置选项\n */\n constructor(options?: TimezoneDateOptions | TimezoneDate) {\n this.#options =\n (options instanceof TimezoneDate\n ? {\n timestamp: options.getTime(),\n utcOffset: options.getUTCOffset(),\n }\n : options) || {};\n const { utcOffset, timestamp, value } = this.#options;\n this.#targetTimezoneOffset = isNumber(utcOffset)\n ? TimezoneDate.getTimezoneOffset(utcOffset)\n : this.#localTimezoneOffset;\n this.#targetTimezoneOffsetMS = this.#targetTimezoneOffset * TIMEZONE_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTimezoneOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS - this.#targetTimezoneOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);\n }\n\n /**\n * 更新内部时间戳\n */\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTimezoneOffsetMS - this.#localTimezoneOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);\n }\n\n /**\n * 获取时区偏移量(分钟)\n * @returns 时区偏移量\n */\n getTimezoneOffset() {\n return this.#targetTimezoneOffset;\n }\n\n /**\n * 获取时区偏移量(UTC)\n * @returns 时区序号\n */\n getUTCOffset() {\n return TimezoneDate.getUTCOffset(this.#targetTimezoneOffset);\n }\n\n /**\n * 获取年份\n * @returns 年份\n */\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n /**\n * 获取月份\n * @returns 月份 (0-11)\n */\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n /**\n * 获取日期\n * @returns 日期 (1-31)\n */\n getDate() {\n return this.#targetDate.getDate();\n }\n\n /**\n * 获取小时\n * @returns 小时 (0-23)\n */\n getHours() {\n return this.#targetDate.getHours();\n }\n\n /**\n * 获取分钟\n * @returns 分钟 (0-59)\n */\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n /**\n * 获取秒数\n * @returns 秒数 (0-59)\n */\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n /**\n * 获取毫秒\n * @returns 毫秒 (0-999)\n */\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n /**\n * 设置年份\n * @param year - 年份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置月份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置日期\n * @param date - 日期\n * @returns 时间戳\n */\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 设置小时\n * @param hours - 小时\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置分钟\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置秒数\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置毫秒\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 获取时间戳\n * @returns 时间戳\n */\n getTime() {\n return this.#timestamp;\n }\n\n /**\n * 获取星期几\n * @returns 星期几 (0-6, 0表示周日)\n */\n getDay() {\n return this.#targetDate.getDay();\n }\n\n /**\n * 转换为 ISO 格式的字符串\n * @returns ISO 格式的时间字符串\n */\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 转换为指定时区的 TimezoneDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TimezoneDate 对象\n * @example\n * ```js\n * // 转换为 UTC 时间\n * const utc0Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 0);\n *\n * // 转换为东八区时间\n * const utc8Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 8);\n * ```\n */\n static changeUtcOffset(td: TimezoneDate, utcOffset: number) {\n return new TimezoneDate({\n utcOffset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区分钟偏移量\n * @param utcOffset - 默认使用当前时区\n * @returns 时区分钟偏移量\n */\n static getTimezoneOffset(utcOffset?: number) {\n return isNumber(utcOffset) ? utcOffset * -60 : new Date().getTimezoneOffset();\n }\n\n /**\n * 获取时区序号\n * @param timezoneOffset - 默认使用当前时区分钟偏移量\n * @returns 时区序号\n */\n static getUTCOffset(timezoneOffset = TimezoneDate.getTimezoneOffset()) {\n return timezoneOffset / -60;\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TimezoneDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TimezoneDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TimezoneDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TimezoneDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TimezoneDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TimezoneDate\n ? new TimezoneDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["isNumber","timestamp","isString","isDate"],"mappings":"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"}
package/dist/core.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { isNumber, isDate, isString } from "./type.mjs";
2
- const TZ_OFFSET_MS = 60 * 1e3;
3
- class TzDate {
2
+ const TIMEZONE_OFFSET_MS = 60 * 1e3;
3
+ class TimezoneDate {
4
4
  /**
5
5
  * 内部时间戳
6
6
  */
@@ -16,35 +16,35 @@ class TzDate {
16
16
  /**
17
17
  * 本地时区偏移量(分钟)
18
18
  */
19
- #localTZOffset = TzDate.getOffset();
19
+ #localTimezoneOffset = TimezoneDate.getTimezoneOffset();
20
20
  /**
21
21
  * 本地时区偏移量(毫秒)
22
22
  */
23
- #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;
23
+ #localTimezoneOffsetMS = this.#localTimezoneOffset * TIMEZONE_OFFSET_MS;
24
24
  /**
25
25
  * 目标时区偏移量(分钟)
26
26
  */
27
- #targetTzOffset = 0;
27
+ #targetTimezoneOffset = 0;
28
28
  /**
29
29
  * 目标时区偏移量(毫秒)
30
30
  */
31
- #targetTzOffsetMS = 0;
31
+ #targetTimezoneOffsetMS = 0;
32
32
  /**
33
33
  * 构造函数选项
34
34
  */
35
35
  #options;
36
36
  /**
37
- * 构造一个 TzDate 实例
37
+ * 构造一个 TimezoneDate 实例
38
38
  * @param options - 配置选项
39
39
  */
40
40
  constructor(options) {
41
- this.#options = (options instanceof TzDate ? {
41
+ this.#options = (options instanceof TimezoneDate ? {
42
42
  timestamp: options.getTime(),
43
- offset: options.getTimezoneOffset()
43
+ utcOffset: options.getUTCOffset()
44
44
  } : options) || {};
45
- const { offset, timestamp, value } = this.#options;
46
- this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;
47
- this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;
45
+ const { utcOffset, timestamp, value } = this.#options;
46
+ this.#targetTimezoneOffset = isNumber(utcOffset) ? TimezoneDate.getTimezoneOffset(utcOffset) : this.#localTimezoneOffset;
47
+ this.#targetTimezoneOffsetMS = this.#targetTimezoneOffset * TIMEZONE_OFFSET_MS;
48
48
  if (Array.isArray(value) && value.length > 0) {
49
49
  const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;
50
50
  const timestamp2 = Date.UTC(
@@ -56,33 +56,33 @@ class TzDate {
56
56
  seconds ?? 0,
57
57
  milliseconds ?? 0
58
58
  );
59
- this.#timestamp = timestamp2 + this.#targetTzOffsetMS;
59
+ this.#timestamp = timestamp2 + this.#targetTimezoneOffsetMS;
60
60
  } else {
61
61
  this.#timestamp = timestamp || Date.now();
62
62
  }
63
- this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);
64
- this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
63
+ this.#targetDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS - this.#targetTimezoneOffsetMS);
64
+ this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);
65
65
  }
66
66
  /**
67
67
  * 更新内部时间戳
68
68
  */
69
69
  #updateTimestamp() {
70
- this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;
71
- this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);
70
+ this.#timestamp = this.#targetDate.getTime() + this.#targetTimezoneOffsetMS - this.#localTimezoneOffsetMS;
71
+ this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);
72
72
  }
73
73
  /**
74
74
  * 获取时区偏移量(分钟)
75
75
  * @returns 时区偏移量
76
76
  */
77
77
  getTimezoneOffset() {
78
- return this.#targetTzOffset;
78
+ return this.#targetTimezoneOffset;
79
79
  }
80
80
  /**
81
- * 获取时区序号
81
+ * 获取时区偏移量(UTC)
82
82
  * @returns 时区序号
83
83
  */
84
- getTimezoneOrder() {
85
- return TzDate.getOrder(this.#targetTzOffset);
84
+ getUTCOffset() {
85
+ return TimezoneDate.getUTCOffset(this.#targetTimezoneOffset);
86
86
  }
87
87
  /**
88
88
  * 获取年份
@@ -243,40 +243,44 @@ class TzDate {
243
243
  return dateFormat(this.#utcDate, "YYYY-MM-DDTHH:mm:ss.SSSZ");
244
244
  }
245
245
  /**
246
- * 创建一个 TzDate 对象
246
+ * 转换为指定时区的 TimezoneDate 对象
247
247
  * @param td - 需要转换的日期对象
248
248
  * @param offset - 目标时区分钟偏移量,默认为当前时区
249
- * @returns 返回一个 TzDate 对象
249
+ * @returns 返回一个 TimezoneDate 对象
250
250
  * @example
251
251
  * ```js
252
- * const tzDate = TzDate.from(new TzDate());
252
+ * // 转换为 UTC 时间
253
+ * const utc0Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 0);
254
+ *
255
+ * // 转换为东八区时间
256
+ * const utc8Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 8);
253
257
  * ```
254
258
  */
255
- static from(td, offset = TzDate.getOffset()) {
256
- return new TzDate({
257
- offset,
259
+ static changeUtcOffset(td, utcOffset) {
260
+ return new TimezoneDate({
261
+ utcOffset,
258
262
  timestamp: td.getTime()
259
263
  });
260
264
  }
261
265
  /**
262
- * 获取时区序号
263
- * @param offset - 默认使用当前时区分钟偏移量
264
- * @returns 时区序号
266
+ * 获取时区分钟偏移量
267
+ * @param utcOffset - 默认使用当前时区
268
+ * @returns 时区分钟偏移量
265
269
  */
266
- static getOrder(offset = TzDate.getOffset()) {
267
- return offset / -60;
270
+ static getTimezoneOffset(utcOffset) {
271
+ return isNumber(utcOffset) ? utcOffset * -60 : (/* @__PURE__ */ new Date()).getTimezoneOffset();
268
272
  }
269
273
  /**
270
- * 获取时区分钟偏移量
271
- * @param gmtOrder - 默认使用当前时区序号
272
- * @returns 时区分钟偏移量
274
+ * 获取时区序号
275
+ * @param timezoneOffset - 默认使用当前时区分钟偏移量
276
+ * @returns 时区序号
273
277
  */
274
- static getOffset(gmtOrder) {
275
- return isNumber(gmtOrder) ? gmtOrder * -60 : (/* @__PURE__ */ new Date()).getTimezoneOffset();
278
+ static getUTCOffset(timezoneOffset = TimezoneDate.getTimezoneOffset()) {
279
+ return timezoneOffset / -60;
276
280
  }
277
281
  }
278
282
  function isValidDate(unknown) {
279
- return unknown instanceof Date && !Number.isNaN(unknown.getTime()) || unknown instanceof TzDate && !Number.isNaN(unknown.getTime());
283
+ return unknown instanceof Date && !Number.isNaN(unknown.getTime()) || unknown instanceof TimezoneDate && !Number.isNaN(unknown.getTime());
280
284
  }
281
285
  function _guessDateSeparator(value) {
282
286
  if (!isString(value)) return;
@@ -300,7 +304,7 @@ function _guessDateTimezone(value) {
300
304
  return d;
301
305
  }
302
306
  function dateParse(dateValue) {
303
- const d1 = isDate(dateValue) ? new Date(dateValue) : dateValue instanceof TzDate ? new TzDate(dateValue) : new Date(dateValue);
307
+ const d1 = isDate(dateValue) ? new Date(dateValue) : dateValue instanceof TimezoneDate ? new TimezoneDate(dateValue) : new Date(dateValue);
304
308
  if (isValidDate(d1)) return d1;
305
309
  const d2 = _guessDateSeparator(dateValue);
306
310
  if (isValidDate(d2)) return d2;
@@ -351,7 +355,7 @@ function dateFormat(dateValue, format = "YYYY-MM-DD HH:mm:ss") {
351
355
  return result;
352
356
  }
353
357
  export {
354
- TzDate as T,
358
+ TimezoneDate as T,
355
359
  dateFormat as a,
356
360
  dateParse as d,
357
361
  isValidDate as i
package/dist/core.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"core.mjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TzDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * 时区偏移量,单位为分钟,默认为当前时区\n */\n offset?: number;\n};\n\n/**\n * 时区偏移量毫秒常量(1分钟 = 60 * 1000 毫秒)\n */\nconst TZ_OFFSET_MS = 60 * 1000;\n\n/**\n * 时区日期类,用于处理不同时区的日期时间\n */\nexport class TzDate {\n /**\n * 内部时间戳\n */\n #timestamp: number;\n\n /**\n * 目标时区的日期对象\n */\n #targetDate: Date;\n\n /**\n * UTC 日期对象\n */\n #utcDate: Date;\n\n /**\n * 本地时区偏移量(分钟)\n */\n #localTZOffset = TzDate.getOffset();\n\n /**\n * 本地时区偏移量(毫秒)\n */\n #localTzOffsetMS = this.#localTZOffset * TZ_OFFSET_MS;\n\n /**\n * 目标时区偏移量(分钟)\n */\n #targetTzOffset = 0;\n\n /**\n * 目标时区偏移量(毫秒)\n */\n #targetTzOffsetMS = 0;\n\n /**\n * 构造函数选项\n */\n #options: TzDateOptions;\n\n /**\n * 构造一个 TzDate 实例\n * @param options - 配置选项\n */\n constructor(options?: TzDateOptions | TzDate) {\n this.#options =\n (options instanceof TzDate\n ? {\n timestamp: options.getTime(),\n offset: options.getTimezoneOffset(),\n }\n : options) || {};\n const { offset, timestamp, value } = this.#options;\n this.#targetTzOffset = isNumber(offset) ? offset : this.#localTZOffset;\n this.#targetTzOffsetMS = this.#targetTzOffset * TZ_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTzOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTzOffsetMS - this.#targetTzOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n /**\n * 更新内部时间戳\n */\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTzOffsetMS - this.#localTzOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTzOffsetMS);\n }\n\n /**\n * 获取时区偏移量(分钟)\n * @returns 时区偏移量\n */\n getTimezoneOffset() {\n return this.#targetTzOffset;\n }\n\n /**\n * 获取时区序号\n * @returns 时区序号\n */\n getTimezoneOrder() {\n return TzDate.getOrder(this.#targetTzOffset);\n }\n\n /**\n * 获取年份\n * @returns 年份\n */\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n /**\n * 获取月份\n * @returns 月份 (0-11)\n */\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n /**\n * 获取日期\n * @returns 日期 (1-31)\n */\n getDate() {\n return this.#targetDate.getDate();\n }\n\n /**\n * 获取小时\n * @returns 小时 (0-23)\n */\n getHours() {\n return this.#targetDate.getHours();\n }\n\n /**\n * 获取分钟\n * @returns 分钟 (0-59)\n */\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n /**\n * 获取秒数\n * @returns 秒数 (0-59)\n */\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n /**\n * 获取毫秒\n * @returns 毫秒 (0-999)\n */\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n /**\n * 设置年份\n * @param year - 年份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置月份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置日期\n * @param date - 日期\n * @returns 时间戳\n */\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 设置小时\n * @param hours - 小时\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置分钟\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置秒数\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置毫秒\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 获取时间戳\n * @returns 时间戳\n */\n getTime() {\n return this.#timestamp;\n }\n\n /**\n * 获取星期几\n * @returns 星期几 (0-6, 0表示周日)\n */\n getDay() {\n return this.#targetDate.getDay();\n }\n\n /**\n * 转换为 ISO 格式的字符串\n * @returns ISO 格式的时间字符串\n */\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 创建一个 TzDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TzDate 对象\n * @example\n * ```js\n * const tzDate = TzDate.from(new TzDate());\n * ```\n */\n static from(td: TzDate, offset = TzDate.getOffset()) {\n return new TzDate({\n offset: offset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区序号\n * @param offset - 默认使用当前时区分钟偏移量\n * @returns 时区序号\n */\n static getOrder(offset = TzDate.getOffset()) {\n return offset / -60;\n }\n\n /**\n * 获取时区分钟偏移量\n * @param gmtOrder - 默认使用当前时区序号\n * @returns 时区分钟偏移量\n */\n static getOffset(gmtOrder?: number) {\n return isNumber(gmtOrder) ? gmtOrder * -60 : new Date().getTimezoneOffset();\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TzDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TzDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TzDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TzDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TzDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TzDate\n ? new TzDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["timestamp"],"mappings":"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"}
1
+ {"version":3,"file":"core.mjs","sources":["../src/date/timezone.ts","../src/date/core.ts"],"sourcesContent":["import { isNumber } from '../type';\nimport { dateFormat } from './core';\n\nexport type TimezoneDateOptions = {\n /**\n * 时间戳\n * @default Date.now()\n */\n timestamp?: number;\n\n /**\n * 日期值\n */\n value?: readonly [\n year?: number,\n month?: number,\n day?: number,\n hours?: number,\n minutes?: number,\n seconds?: number,\n milliseconds?: number,\n ];\n\n /**\n * UTC 时区,支持负数和小数,例如:\n * - 8 表示 UTC+8\n * - -12 表示 UTC-12\n * - 0 表示 UTC 时间\n * - 12.5 表示 UTC+12:30\n */\n utcOffset?: number;\n};\n\n/**\n * 时区偏移量毫秒常量(1分钟 = 60 * 1000 毫秒)\n */\nconst TIMEZONE_OFFSET_MS = 60 * 1000;\n\n/**\n * 时区日期类,用于处理不同时区的日期时间\n */\nexport class TimezoneDate {\n /**\n * 内部时间戳\n */\n #timestamp: number;\n\n /**\n * 目标时区的日期对象\n */\n #targetDate: Date;\n\n /**\n * UTC 日期对象\n */\n #utcDate: Date;\n\n /**\n * 本地时区偏移量(分钟)\n */\n #localTimezoneOffset = TimezoneDate.getTimezoneOffset();\n\n /**\n * 本地时区偏移量(毫秒)\n */\n #localTimezoneOffsetMS = this.#localTimezoneOffset * TIMEZONE_OFFSET_MS;\n\n /**\n * 目标时区偏移量(分钟)\n */\n #targetTimezoneOffset = 0;\n\n /**\n * 目标时区偏移量(毫秒)\n */\n #targetTimezoneOffsetMS = 0;\n\n /**\n * 构造函数选项\n */\n #options: TimezoneDateOptions;\n\n /**\n * 构造一个 TimezoneDate 实例\n * @param options - 配置选项\n */\n constructor(options?: TimezoneDateOptions | TimezoneDate) {\n this.#options =\n (options instanceof TimezoneDate\n ? {\n timestamp: options.getTime(),\n utcOffset: options.getUTCOffset(),\n }\n : options) || {};\n const { utcOffset, timestamp, value } = this.#options;\n this.#targetTimezoneOffset = isNumber(utcOffset)\n ? TimezoneDate.getTimezoneOffset(utcOffset)\n : this.#localTimezoneOffset;\n this.#targetTimezoneOffsetMS = this.#targetTimezoneOffset * TIMEZONE_OFFSET_MS;\n\n if (Array.isArray(value) && value.length > 0) {\n const [fullYear, month, day, hours, minutes, seconds, milliseconds] = value;\n const timestamp = Date.UTC(\n fullYear ?? 0,\n month ?? 0,\n day ?? 1,\n hours ?? 0,\n minutes ?? 0,\n seconds ?? 0,\n milliseconds ?? 0,\n );\n\n this.#timestamp = timestamp + this.#targetTimezoneOffsetMS;\n } else {\n this.#timestamp = timestamp || Date.now();\n }\n\n this.#targetDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS - this.#targetTimezoneOffsetMS);\n this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);\n }\n\n /**\n * 更新内部时间戳\n */\n #updateTimestamp() {\n this.#timestamp = this.#targetDate.getTime() + this.#targetTimezoneOffsetMS - this.#localTimezoneOffsetMS;\n this.#utcDate = new Date(this.#timestamp + this.#localTimezoneOffsetMS);\n }\n\n /**\n * 获取时区偏移量(分钟)\n * @returns 时区偏移量\n */\n getTimezoneOffset() {\n return this.#targetTimezoneOffset;\n }\n\n /**\n * 获取时区偏移量(UTC)\n * @returns 时区序号\n */\n getUTCOffset() {\n return TimezoneDate.getUTCOffset(this.#targetTimezoneOffset);\n }\n\n /**\n * 获取年份\n * @returns 年份\n */\n getFullYear() {\n return this.#targetDate.getFullYear();\n }\n\n /**\n * 获取月份\n * @returns 月份 (0-11)\n */\n getMonth() {\n return this.#targetDate.getMonth();\n }\n\n /**\n * 获取日期\n * @returns 日期 (1-31)\n */\n getDate() {\n return this.#targetDate.getDate();\n }\n\n /**\n * 获取小时\n * @returns 小时 (0-23)\n */\n getHours() {\n return this.#targetDate.getHours();\n }\n\n /**\n * 获取分钟\n * @returns 分钟 (0-59)\n */\n getMinutes() {\n return this.#targetDate.getMinutes();\n }\n\n /**\n * 获取秒数\n * @returns 秒数 (0-59)\n */\n getSeconds() {\n return this.#targetDate.getSeconds();\n }\n\n /**\n * 获取毫秒\n * @returns 毫秒 (0-999)\n */\n getMilliseconds() {\n return this.#targetDate.getMilliseconds();\n }\n\n /**\n * 设置年份\n * @param year - 年份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setFullYear(year: number, month?: number, date?: number) {\n this.#targetDate.setFullYear(year);\n this.#updateTimestamp();\n\n if (isNumber(month)) this.setMonth(month);\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置月份\n * @param month - 月份\n * @param date - 日期\n * @returns 时间戳\n */\n setMonth(month: number, date?: number) {\n this.#targetDate.setMonth(month);\n this.#updateTimestamp();\n\n if (isNumber(date)) this.setDate(date);\n\n return this.getTime();\n }\n\n /**\n * 设置日期\n * @param date - 日期\n * @returns 时间戳\n */\n setDate(date: number) {\n this.#targetDate.setDate(date);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 设置小时\n * @param hours - 小时\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setHours(hours: number, minutes?: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setHours(hours);\n this.#updateTimestamp();\n\n if (isNumber(minutes)) this.setMinutes(minutes);\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置分钟\n * @param minutes - 分钟\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMinutes(minutes: number, seconds?: number, milliseconds?: number) {\n this.#targetDate.setMinutes(minutes);\n this.#updateTimestamp();\n\n if (isNumber(seconds)) this.setSeconds(seconds);\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置秒数\n * @param seconds - 秒数\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setSeconds(seconds: number, milliseconds?: number) {\n this.#targetDate.setSeconds(seconds);\n this.#updateTimestamp();\n\n if (isNumber(milliseconds)) this.setMilliseconds(milliseconds);\n\n return this.getTime();\n }\n\n /**\n * 设置毫秒\n * @param milliseconds - 毫秒\n * @returns 时间戳\n */\n setMilliseconds(milliseconds: number) {\n this.#targetDate.setMilliseconds(milliseconds);\n this.#updateTimestamp();\n\n return this.getTime();\n }\n\n /**\n * 获取时间戳\n * @returns 时间戳\n */\n getTime() {\n return this.#timestamp;\n }\n\n /**\n * 获取星期几\n * @returns 星期几 (0-6, 0表示周日)\n */\n getDay() {\n return this.#targetDate.getDay();\n }\n\n /**\n * 转换为 ISO 格式的字符串\n * @returns ISO 格式的时间字符串\n */\n toISOString() {\n return dateFormat(this.#utcDate, 'YYYY-MM-DDTHH:mm:ss.SSSZ');\n }\n\n /**\n * 转换为指定时区的 TimezoneDate 对象\n * @param td - 需要转换的日期对象\n * @param offset - 目标时区分钟偏移量,默认为当前时区\n * @returns 返回一个 TimezoneDate 对象\n * @example\n * ```js\n * // 转换为 UTC 时间\n * const utc0Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 0);\n *\n * // 转换为东八区时间\n * const utc8Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 8);\n * ```\n */\n static changeUtcOffset(td: TimezoneDate, utcOffset: number) {\n return new TimezoneDate({\n utcOffset,\n timestamp: td.getTime(),\n });\n }\n\n /**\n * 获取时区分钟偏移量\n * @param utcOffset - 默认使用当前时区\n * @returns 时区分钟偏移量\n */\n static getTimezoneOffset(utcOffset?: number) {\n return isNumber(utcOffset) ? utcOffset * -60 : new Date().getTimezoneOffset();\n }\n\n /**\n * 获取时区序号\n * @param timezoneOffset - 默认使用当前时区分钟偏移量\n * @returns 时区序号\n */\n static getUTCOffset(timezoneOffset = TimezoneDate.getTimezoneOffset()) {\n return timezoneOffset / -60;\n }\n}\n","import { objectEach } from '@/object';\nimport { isDate, isString } from '@/type';\nimport { TimezoneDate } from './timezone';\n\n/**\n * 判断一个值是否为有效的日期对象\n * @param unknown - 需要判断的值\n * @returns 如果值是有效的日期对象则返回 true,否则返回 false\n * @example\n * ```typescript\n * isValidDate(new Date()); // true\n * isValidDate('2023-01-01'); // false\n * isValidDate(NaN); // false\n * ```\n */\nexport function isValidDate(unknown: unknown): unknown is Date | TimezoneDate {\n return (\n (unknown instanceof Date && !Number.isNaN(unknown.getTime())) ||\n (unknown instanceof TimezoneDate && !Number.isNaN(unknown.getTime()))\n );\n}\n\nexport type DateLike = Date | TimezoneDate;\nexport type DateValue = number | string | DateLike;\n\nfunction _guessDateSeparator(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const value2 = value.replace(/-/g, '/');\n\n return new Date(value2);\n}\n\nfunction _guessDateTimezone(value: DateValue): Date | undefined {\n if (!isString(value)) return;\n\n const re = /([+-])(\\d\\d)(\\d\\d)$/;\n\n const matches = re.exec(value);\n\n if (!matches) return;\n\n const value2 = value.replace(re, 'Z');\n const d = new Date(value2);\n\n if (!isValidDate(d)) return;\n\n const [, flag, hours, minutes] = matches;\n const hours2 = Number.parseInt(hours, 10);\n const minutes2 = Number.parseInt(minutes, 10);\n const offset = (a: number, b: number): number => (flag === '+' ? a - b : a + b);\n\n d.setHours(offset(d.getHours(), hours2));\n d.setMinutes(offset(d.getMinutes(), minutes2));\n\n return d;\n}\n\n/**\n * 解析为Date对象\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @returns 解析后的 Date 对象\n * @throws {SyntaxError} 如果无法解析为有效的日期对象,则抛出错误\n * @example\n * ```typescript\n * dateParse('2023-01-01'); // Date对象\n * dateParse(1672531200000); // Date对象\n * dateParse(new Date()); // Date对象\n * dateParse('invalid date'); // 抛出 SyntaxError\n * ```\n */\nexport function dateParse(dateValue: DateValue): DateLike {\n // 传入的 Date 对象有 Date、TimezoneDate\n // @ts-ignore\n const d1 = isDate(dateValue)\n ? new Date(dateValue)\n : dateValue instanceof TimezoneDate\n ? new TimezoneDate(dateValue)\n : new Date(dateValue);\n if (isValidDate(d1)) return d1;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26 18:06:15') 返回值是一个非法日期对象\n const d2 = _guessDateSeparator(dateValue);\n if (isValidDate(d2)) return d2;\n\n // safari 浏览器的日期解析有问题\n // new Date('2020-06-26T18:06:15.000+0800') 返回值是一个非法日期对象\n const d3 = _guessDateTimezone(dateValue);\n if (isValidDate(d3)) return d3;\n\n throw new SyntaxError(`${dateValue.toString()} 不是一个合法的日期值`);\n}\n\nfunction _pad(num: number, len = 2) {\n return `${num}`.padStart(len, '0');\n}\n\nconst rules: [RegExp, (date: DateLike) => number | string][] = [\n [/Y{4}/gi, (date) => date.getFullYear()],\n [/Y{2}/gi, (date) => date.getFullYear() % 100],\n [/M{2}/g, (date) => _pad(date.getMonth() + 1)],\n [/M{1}/g, (date) => date.getMonth() + 1],\n [/D{2}/gi, (date) => _pad(date.getDate())],\n [/D{1}/gi, (date) => date.getDate()],\n [/H{2}/g, (date) => _pad(date.getHours())],\n [/H{1}/g, (date) => date.getHours()],\n [\n /h{2}/g,\n (date) => {\n const h = date.getHours();\n return _pad(h > 12 ? h - 12 : h);\n },\n ],\n [\n /h{1}/g,\n (date) => {\n const h = date.getHours();\n return h > 12 ? h - 12 : h;\n },\n ],\n [/m{2}/g, (date) => _pad(date.getMinutes())],\n [/m{1}/g, (date) => date.getMinutes()],\n [/s{2}/g, (date) => _pad(date.getSeconds())],\n [/s{1}/g, (date) => date.getSeconds()],\n [/S{3}/g, (date) => _pad(date.getMilliseconds(), 3)],\n [/S{2}/g, (date) => _pad(date.getMilliseconds(), 2)],\n [/S{1}/g, (date) => date.getMilliseconds()],\n];\n\n/**\n * 格式化为日期字符串(带自定义格式化模板)\n * @param dateValue - 可以是数值、字符串或 Date 对象\n * @param format - 模板,默认是 'YYYY-MM-DD HH:mm:ss',模板字符:\n * - YYYY:年\n * - yyyy: 年\n * - MM:月\n * - DD:日\n * - dd: 日\n * - HH:时(24 小时制)\n * - hh:时(12 小时制)\n * - mm:分\n * - ss:秒\n * - SSS:毫秒\n * @returns 格式化后的日期字符串\n * @example\n * ```typescript\n * dateFormat(new Date(), 'YYYY-MM-DD'); // '2023-01-01'\n * dateFormat(1672531200000, 'YYYY/MM/DD HH:mm:ss'); // '2023/01/01 00:00:00'\n * dateFormat('2023-01-01', 'YYYY年MM月DD日'); // '2023年01月01日'\n * ```\n */\nexport function dateFormat(dateValue: DateValue, format = 'YYYY-MM-DD HH:mm:ss'): string {\n const date = dateParse(dateValue);\n let result = format;\n\n for (const rule of rules) {\n result = result.replace(rule[0], String(rule[1](date)));\n }\n\n return result;\n}\n"],"names":["timestamp"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { TzDate } from './timezone';
1
+ import { TimezoneDate } from './timezone';
2
2
  /**
3
3
  * 判断一个值是否为有效的日期对象
4
4
  * @param unknown - 需要判断的值
@@ -10,8 +10,8 @@ import { TzDate } from './timezone';
10
10
  * isValidDate(NaN); // false
11
11
  * ```
12
12
  */
13
- export declare function isValidDate(unknown: unknown): unknown is Date | TzDate;
14
- export type DateLike = Date | TzDate;
13
+ export declare function isValidDate(unknown: unknown): unknown is Date | TimezoneDate;
14
+ export type DateLike = Date | TimezoneDate;
15
15
  export type DateValue = number | string | DateLike;
16
16
  /**
17
17
  * 解析为Date对象
@@ -1,4 +1,4 @@
1
- export type TzDateOptions = {
1
+ export type TimezoneDateOptions = {
2
2
  /**
3
3
  * 时间戳
4
4
  * @default Date.now()
@@ -17,30 +17,34 @@ export type TzDateOptions = {
17
17
  milliseconds?: number
18
18
  ];
19
19
  /**
20
- * 时区偏移量,单位为分钟,默认为当前时区
20
+ * UTC 时区,支持负数和小数,例如:
21
+ * - 8 表示 UTC+8
22
+ * - -12 表示 UTC-12
23
+ * - 0 表示 UTC 时间
24
+ * - 12.5 表示 UTC+12:30
21
25
  */
22
- offset?: number;
26
+ utcOffset?: number;
23
27
  };
24
28
  /**
25
29
  * 时区日期类,用于处理不同时区的日期时间
26
30
  */
27
- export declare class TzDate {
31
+ export declare class TimezoneDate {
28
32
  #private;
29
33
  /**
30
- * 构造一个 TzDate 实例
34
+ * 构造一个 TimezoneDate 实例
31
35
  * @param options - 配置选项
32
36
  */
33
- constructor(options?: TzDateOptions | TzDate);
37
+ constructor(options?: TimezoneDateOptions | TimezoneDate);
34
38
  /**
35
39
  * 获取时区偏移量(分钟)
36
40
  * @returns 时区偏移量
37
41
  */
38
42
  getTimezoneOffset(): number;
39
43
  /**
40
- * 获取时区序号
44
+ * 获取时区偏移量(UTC)
41
45
  * @returns 时区序号
42
46
  */
43
- getTimezoneOrder(): number;
47
+ getUTCOffset(): number;
44
48
  /**
45
49
  * 获取年份
46
50
  * @returns 年份
@@ -143,26 +147,30 @@ export declare class TzDate {
143
147
  */
144
148
  toISOString(): string;
145
149
  /**
146
- * 创建一个 TzDate 对象
150
+ * 转换为指定时区的 TimezoneDate 对象
147
151
  * @param td - 需要转换的日期对象
148
152
  * @param offset - 目标时区分钟偏移量,默认为当前时区
149
- * @returns 返回一个 TzDate 对象
153
+ * @returns 返回一个 TimezoneDate 对象
150
154
  * @example
151
155
  * ```js
152
- * const tzDate = TzDate.from(new TzDate());
156
+ * // 转换为 UTC 时间
157
+ * const utc0Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 0);
158
+ *
159
+ * // 转换为东八区时间
160
+ * const utc8Td = TimezoneDate.changeUtcOffset(new TimezoneDate(), 8);
153
161
  * ```
154
162
  */
155
- static from(td: TzDate, offset?: number): TzDate;
156
- /**
157
- * 获取时区序号
158
- * @param offset - 默认使用当前时区分钟偏移量
159
- * @returns 时区序号
160
- */
161
- static getOrder(offset?: number): number;
163
+ static changeUtcOffset(td: TimezoneDate, utcOffset: number): TimezoneDate;
162
164
  /**
163
165
  * 获取时区分钟偏移量
164
- * @param gmtOrder - 默认使用当前时区序号
166
+ * @param utcOffset - 默认使用当前时区
165
167
  * @returns 时区分钟偏移量
166
168
  */
167
- static getOffset(gmtOrder?: number): number;
169
+ static getTimezoneOffset(utcOffset?: number): number;
170
+ /**
171
+ * 获取时区序号
172
+ * @param timezoneOffset - 默认使用当前时区分钟偏移量
173
+ * @returns 时区序号
174
+ */
175
+ static getUTCOffset(timezoneOffset?: number): number;
168
176
  }
package/dist/date.cjs CHANGED
@@ -206,7 +206,7 @@ exports.DATE_MINUTE_MS = _const.DATE_MINUTE_MS;
206
206
  exports.DATE_MONTH_MS = _const.DATE_MONTH_MS;
207
207
  exports.DATE_SECOND_MS = _const.DATE_SECOND_MS;
208
208
  exports.DATE_YEAR_MS = _const.DATE_YEAR_MS;
209
- exports.TzDate = core.TzDate;
209
+ exports.TimezoneDate = core.TimezoneDate;
210
210
  exports.dateFormat = core.dateFormat;
211
211
  exports.dateParse = core.dateParse;
212
212
  exports.isValidDate = core.isValidDate;
package/dist/date.mjs CHANGED
@@ -208,7 +208,7 @@ export {
208
208
  e as DATE_SECOND_MS,
209
209
  D as DATE_YEAR_MS,
210
210
  EWeekStart,
211
- T as TzDate,
211
+ T as TimezoneDate,
212
212
  _dateWeeks,
213
213
  dateDaysInMonth,
214
214
  dateDaysInYear,
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const VERSION = "1.15.6";
3
+ const VERSION = "1.16.0";
4
4
  exports.VERSION = VERSION;
5
5
  //# sourceMappingURL=index.cjs.map
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- const VERSION = "1.15.6";
1
+ const VERSION = "1.16.0";
2
2
  export {
3
3
  VERSION
4
4
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcome/utils-core",
3
- "version": "1.15.7",
3
+ "version": "1.17.0",
4
4
  "description": "cloudcome core utils",
5
5
  "engines": {
6
6
  "node": ">=22"