sculp-js 1.19.1 → 1.19.3

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.
Files changed (63) hide show
  1. package/dist/cjs/array.cjs +1 -1
  2. package/dist/cjs/async.cjs +1 -1
  3. package/dist/cjs/base64.cjs +157 -71
  4. package/dist/cjs/clipboard.cjs +1 -1
  5. package/dist/cjs/cloneDeep.cjs +1 -1
  6. package/dist/cjs/cookie.cjs +1 -1
  7. package/dist/cjs/date.cjs +130 -70
  8. package/dist/cjs/dom.cjs +1 -1
  9. package/dist/cjs/download.cjs +1 -1
  10. package/dist/cjs/file.cjs +1 -1
  11. package/dist/cjs/func.cjs +1 -1
  12. package/dist/cjs/index.cjs +11 -3
  13. package/dist/cjs/isEqual.cjs +1 -1
  14. package/dist/cjs/math.cjs +1 -1
  15. package/dist/cjs/number.cjs +1 -1
  16. package/dist/cjs/object.cjs +1 -1
  17. package/dist/cjs/path.cjs +1 -1
  18. package/dist/cjs/qs.cjs +1 -1
  19. package/dist/cjs/random.cjs +1 -1
  20. package/dist/cjs/string.cjs +1 -1
  21. package/dist/cjs/tooltip.cjs +1 -1
  22. package/dist/cjs/tree.cjs +1 -1
  23. package/dist/cjs/type.cjs +71 -3
  24. package/dist/cjs/unicodeToolkit.cjs +19 -19
  25. package/dist/cjs/unique.cjs +1 -1
  26. package/dist/cjs/url.cjs +1 -1
  27. package/dist/cjs/validator.cjs +1 -1
  28. package/dist/cjs/variable.cjs +1 -1
  29. package/dist/cjs/watermark.cjs +1 -1
  30. package/dist/esm/array.mjs +1 -1
  31. package/dist/esm/async.mjs +1 -1
  32. package/dist/esm/base64.mjs +157 -71
  33. package/dist/esm/clipboard.mjs +1 -1
  34. package/dist/esm/cloneDeep.mjs +1 -1
  35. package/dist/esm/cookie.mjs +1 -1
  36. package/dist/esm/date.mjs +130 -78
  37. package/dist/esm/dom.mjs +1 -1
  38. package/dist/esm/download.mjs +1 -1
  39. package/dist/esm/file.mjs +1 -1
  40. package/dist/esm/func.mjs +1 -1
  41. package/dist/esm/index.mjs +11 -10
  42. package/dist/esm/isEqual.mjs +1 -1
  43. package/dist/esm/math.mjs +1 -1
  44. package/dist/esm/number.mjs +1 -1
  45. package/dist/esm/object.mjs +1 -1
  46. package/dist/esm/path.mjs +1 -1
  47. package/dist/esm/qs.mjs +1 -1
  48. package/dist/esm/random.mjs +1 -1
  49. package/dist/esm/string.mjs +1 -1
  50. package/dist/esm/tooltip.mjs +1 -1
  51. package/dist/esm/tree.mjs +1 -1
  52. package/dist/esm/type.mjs +71 -3
  53. package/dist/esm/unicodeToolkit.mjs +19 -19
  54. package/dist/esm/unique.mjs +1 -1
  55. package/dist/esm/url.mjs +1 -1
  56. package/dist/esm/validator.mjs +1 -1
  57. package/dist/esm/variable.mjs +1 -1
  58. package/dist/esm/watermark.mjs +1 -1
  59. package/dist/types/base64.d.ts +6 -6
  60. package/dist/types/date.d.ts +124 -28
  61. package/dist/types/type.d.ts +86 -3
  62. package/dist/umd/index.min.js +2 -2
  63. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -15,112 +15,198 @@ const b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
15
15
  // eslint-disable-next-line
16
16
  const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
17
17
  /**
18
- * 字符串编码成Base64, 平替浏览器的btoa, 不包含中文的处理 (适用于任何环境,包括小程序)
18
+ * 高性能 UTF-8 字符串转 Uint8Array
19
+ */
20
+ function stringToUint8Array(str) {
21
+ const len = str.length;
22
+ const bytes = new Uint8Array(len * 3); // 最多 3 倍长度
23
+ let j = 0;
24
+ for (let i = 0; i < len; i++) {
25
+ let code = str.charCodeAt(i);
26
+ if (code < 0x80) {
27
+ bytes[j++] = code;
28
+ } else if (code < 0x800) {
29
+ bytes[j++] = 0xc0 | (code >> 6);
30
+ bytes[j++] = 0x80 | (code & 0x3f);
31
+ } else if (code < 0xd800 || code >= 0xe000) {
32
+ bytes[j++] = 0xe0 | (code >> 12);
33
+ bytes[j++] = 0x80 | ((code >> 6) & 0x3f);
34
+ bytes[j++] = 0x80 | (code & 0x3f);
35
+ } else {
36
+ // 处理代理对(emoji 等)
37
+ i++;
38
+ code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
39
+ bytes[j++] = 0xf0 | (code >> 18);
40
+ bytes[j++] = 0x80 | ((code >> 12) & 0x3f);
41
+ bytes[j++] = 0x80 | ((code >> 6) & 0x3f);
42
+ bytes[j++] = 0x80 | (code & 0x3f);
43
+ }
44
+ }
45
+ return bytes.subarray(0, j);
46
+ }
47
+ /**
48
+ * 高性能 Uint8Array 转 UTF-8 字符串
49
+ */
50
+ function uint8ArrayToString(bytes) {
51
+ const len = bytes.length;
52
+ let result = '';
53
+ let i = 0;
54
+ while (i < len) {
55
+ const byte1 = bytes[i++];
56
+ if (byte1 < 0x80) {
57
+ result += String.fromCharCode(byte1);
58
+ } else if (byte1 < 0xe0) {
59
+ const byte2 = bytes[i++] & 0x3f;
60
+ result += String.fromCharCode(((byte1 & 0x1f) << 6) | byte2);
61
+ } else if (byte1 < 0xf0) {
62
+ const byte2 = bytes[i++] & 0x3f;
63
+ const byte3 = bytes[i++] & 0x3f;
64
+ result += String.fromCharCode(((byte1 & 0x0f) << 12) | (byte2 << 6) | byte3);
65
+ } else {
66
+ const byte2 = bytes[i++] & 0x3f;
67
+ const byte3 = bytes[i++] & 0x3f;
68
+ const byte4 = bytes[i++] & 0x3f;
69
+ let code = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4;
70
+ code -= 0x10000;
71
+ result += String.fromCharCode(0xd800 + ((code >> 10) & 0x3ff), 0xdc00 + (code & 0x3ff));
72
+ }
73
+ }
74
+ return result;
75
+ }
76
+ /**
77
+ * 高性能 Base64 编码(二进制字符串转 Base64)
78
+ */
79
+ function binaryToBase64(binary) {
80
+ const len = binary.length;
81
+ let result = '';
82
+ let i = 0;
83
+ for (; i < len - 2; i += 3) {
84
+ const n = (binary.charCodeAt(i) << 16) | (binary.charCodeAt(i + 1) << 8) | binary.charCodeAt(i + 2);
85
+ result += b64.charAt(n >> 18) + b64.charAt((n >> 12) & 0x3f) + b64.charAt((n >> 6) & 0x3f) + b64.charAt(n & 0x3f);
86
+ }
87
+ // 处理剩余字节
88
+ const remaining = len - i;
89
+ if (remaining === 1) {
90
+ const n = binary.charCodeAt(i);
91
+ result += b64.charAt(n >> 2) + b64.charAt((n << 4) & 0x3f) + '==';
92
+ } else if (remaining === 2) {
93
+ const n = (binary.charCodeAt(i) << 8) | binary.charCodeAt(i + 1);
94
+ result += b64.charAt(n >> 10) + b64.charAt((n >> 4) & 0x3f) + b64.charAt((n << 2) & 0x3f) + '=';
95
+ }
96
+ return result;
97
+ }
98
+ /**
99
+ * 高性能 Base64 解码(Base64 转二进制字符串)
100
+ */
101
+ function base64ToBinary(base64Str) {
102
+ base64Str = String(base64Str).replace(/[\t\n\f\r ]+/g, '');
103
+ if (!b64re.test(base64Str)) {
104
+ throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
105
+ }
106
+ const len = base64Str.length;
107
+ const padding = base64Str.endsWith('==') ? 2 : base64Str.endsWith('=') ? 1 : 0;
108
+ const result = new Array(len * 0.75 - padding);
109
+ let j = 0;
110
+ for (let i = 0; i < len; i += 4) {
111
+ const n =
112
+ (b64.indexOf(base64Str.charAt(i)) << 18) |
113
+ (b64.indexOf(base64Str.charAt(i + 1)) << 12) |
114
+ ((b64.indexOf(base64Str.charAt(i + 2)) & 0x3f) << 6) |
115
+ (b64.indexOf(base64Str.charAt(i + 3)) & 0x3f);
116
+ result[j++] = String.fromCharCode((n >> 16) & 0xff);
117
+ if (i + 2 < len - padding || padding < 2) {
118
+ result[j++] = String.fromCharCode((n >> 8) & 0xff);
119
+ }
120
+ if (i + 3 < len - padding || padding < 1) {
121
+ result[j++] = String.fromCharCode(n & 0xff);
122
+ }
123
+ }
124
+ return result.join('');
125
+ }
126
+ /**
127
+ * 字符串编码成 Base64(适用于任何环境,包括小程序)
19
128
  * @param {string} string
20
129
  * @returns {string}
21
130
  */
22
131
  function weBtoa(string) {
23
- // 同window.btoa: 字符串编码成Base64
24
132
  string = String(string);
25
- let bitmap,
26
- a,
27
- b,
28
- c,
29
- result = '',
30
- i = 0;
31
- const strLen = string.length;
32
- const rest = strLen % 3;
33
- for (; i < strLen; ) {
34
- if ((a = string.charCodeAt(i++)) > 255 || (b = string.charCodeAt(i++)) > 255 || (c = string.charCodeAt(i++)) > 255)
133
+ const len = string.length;
134
+ for (let i = 0; i < len; i++) {
135
+ if (string.charCodeAt(i) > 255) {
35
136
  throw new TypeError(
36
137
  "Failed to execute 'btoa' on 'Window': The string to be encoded contains characters outside of the Latin1 range."
37
138
  );
38
- bitmap = (a << 16) | (b << 8) | c;
39
- result +=
40
- b64.charAt((bitmap >> 18) & 63) +
41
- b64.charAt((bitmap >> 12) & 63) +
42
- b64.charAt((bitmap >> 6) & 63) +
43
- b64.charAt(bitmap & 63);
139
+ }
44
140
  }
45
- return rest ? result.slice(0, rest - 3) + '==='.substring(rest) : result;
141
+ return binaryToBase64(string);
46
142
  }
47
143
  /**
48
- * Base64解码为原始字符串,平替浏览器的atob, 不包含中文的处理(适用于任何环境,包括小程序)
144
+ * Base64 解码为原始字符串(适用于任何环境,包括小程序)
49
145
  * @param {string} string
50
146
  * @returns {string}
51
147
  */
52
148
  function weAtob(string) {
53
- // 同window.atob: Base64解码为原始字符串
54
- string = String(string).replace(/[\t\n\f\r ]+/g, '');
55
- if (!b64re.test(string))
56
- throw new TypeError("Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.");
57
- string += '=='.slice(2 - (string.length & 3));
58
- let bitmap,
59
- result = '',
60
- r1,
61
- r2,
62
- i = 0;
63
- for (const strLen = string.length; i < strLen; ) {
64
- bitmap =
65
- (b64.indexOf(string.charAt(i++)) << 18) |
66
- (b64.indexOf(string.charAt(i++)) << 12) |
67
- ((r1 = b64.indexOf(string.charAt(i++))) << 6) |
68
- (r2 = b64.indexOf(string.charAt(i++)));
69
- result +=
70
- r1 === 64
71
- ? String.fromCharCode((bitmap >> 16) & 255)
72
- : r2 === 64
73
- ? String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255)
74
- : String.fromCharCode((bitmap >> 16) & 255, (bitmap >> 8) & 255, bitmap & 255);
75
- }
76
- return result;
77
- }
78
- function stringToUint8Array(str) {
79
- const utf8 = encodeURIComponent(str); // 将字符串转换为 UTF-8 编码
80
- const uint8Array = new Uint8Array(utf8.length); // 创建 Uint8Array
81
- for (let i = 0; i < utf8.length; i++) {
82
- uint8Array[i] = utf8.charCodeAt(i); // 填充 Uint8Array
83
- }
84
- return uint8Array;
85
- }
86
- function uint8ArrayToString(uint8Array) {
87
- const utf8 = String.fromCharCode.apply(null, uint8Array); // 将 Uint8Array 转为字符串
88
- return decodeURIComponent(utf8); // 将 UTF-8 字符串解码回正常字符串
149
+ return base64ToBinary(string);
89
150
  }
90
151
  /**
91
- * 将base64编码的字符串转换为原始字符串,包括对中文内容的处理(高性能,且支持Web、Node、小程序等任意平台)
92
- * @param base64 base64编码的字符串
152
+ * 将 base64 编码的字符串转换为原始字符串,包括对中文内容的处理 (高性能,且支持 Web、Node、小程序等任意平台)
153
+ * @param base64 base64 编码的字符串
93
154
  * @returns 原始字符串,包括中文内容
94
155
  */
95
156
  function b64decode(base64) {
96
- const binaryString = !type.isNullOrUnDef(func.getGlobal('atob')) ? func.getGlobal('atob')(base64) : weAtob(base64);
157
+ // 优先使用原生方法(性能最优)
158
+ if (!type.isNullOrUnDef(func.getGlobal('atob')) && !type.isNullOrUnDef(func.getGlobal('TextDecoder'))) {
159
+ try {
160
+ const binaryString = func.getGlobal('atob')(base64);
161
+ const len = binaryString.length;
162
+ const bytes = new Uint8Array(len);
163
+ for (let i = 0; i < len; i++) {
164
+ bytes[i] = binaryString.charCodeAt(i);
165
+ }
166
+ return new (func.getGlobal('TextDecoder'))('utf-8').decode(bytes);
167
+ } catch (e) {
168
+ // 如果原生方法失败,使用降级方案
169
+ }
170
+ }
171
+ // 降级方案:使用自定义实现
172
+ const binaryString = base64ToBinary(base64);
97
173
  const len = binaryString.length;
98
174
  const bytes = new Uint8Array(len);
99
175
  for (let i = 0; i < len; i++) {
100
176
  bytes[i] = binaryString.charCodeAt(i);
101
177
  }
102
- // 使用TextDecoder将Uint8Array转换为原始字符串,包括中文内容
103
- return !type.isNullOrUnDef(func.getGlobal('TextDecoder'))
104
- ? new (func.getGlobal('TextDecoder'))('utf-8').decode(bytes)
105
- : uint8ArrayToString(bytes);
178
+ return uint8ArrayToString(bytes);
106
179
  }
107
180
  /**
108
- * 将原始字符串,包括中文内容,转换为base64编码的字符串(高性能,且支持Web、Node、小程序等任意平台)
181
+ * 将原始字符串,包括中文内容,转换为 base64 编码的字符串 (高性能,且支持 Web、Node、小程序等任意平台)
109
182
  * @param rawStr 原始字符串,包括中文内容
110
- * @returns base64编码的字符串
183
+ * @returns base64 编码的字符串
111
184
  */
112
185
  function b64encode(rawStr) {
113
- const utf8Array = !type.isNullOrUnDef(func.getGlobal('TextEncoder'))
114
- ? new (func.getGlobal('TextEncoder'))().encode(rawStr)
115
- : stringToUint8Array(rawStr);
186
+ // 优先使用原生方法(性能最优)
187
+ if (!type.isNullOrUnDef(func.getGlobal('btoa')) && !type.isNullOrUnDef(func.getGlobal('TextEncoder'))) {
188
+ try {
189
+ const utf8Array = new (func.getGlobal('TextEncoder'))().encode(rawStr);
190
+ let binaryString = '';
191
+ const len = utf8Array.length;
192
+ for (let i = 0; i < len; i++) {
193
+ binaryString += String.fromCharCode(utf8Array[i]);
194
+ }
195
+ return func.getGlobal('btoa')(binaryString);
196
+ } catch (e) {
197
+ // 如果原生方法失败,使用降级方案
198
+ }
199
+ }
200
+ // 降级方案:使用自定义实现
201
+ const utf8Array = stringToUint8Array(rawStr);
116
202
  // 将 Uint8Array 转换为二进制字符串
117
203
  let binaryString = '';
118
204
  const len = utf8Array.length;
119
205
  for (let i = 0; i < len; i++) {
120
206
  binaryString += String.fromCharCode(utf8Array[i]);
121
207
  }
122
- // 将二进制字符串转换为base64编码的字符串
123
- return !type.isNullOrUnDef(func.getGlobal('btoa')) ? func.getGlobal('btoa')(binaryString) : weBtoa(binaryString);
208
+ // 将二进制字符串转换为 base64 编码
209
+ return binaryToBase64(binaryString);
124
210
  }
125
211
  var base64 = {
126
212
  weBtoa,
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
package/dist/cjs/date.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -115,19 +115,25 @@ function dateToEnd(value) {
115
115
  return dateParse(d.getTime() - 1);
116
116
  }
117
117
  /**
118
- * 格式化为日期对象(带自定义格式化模板)
118
+ * 格式化为日期对象 (带自定义格式化模板)
119
119
  * @param {Date} value - 可以是数值、字符串或 Date 对象
120
120
  * @param {string} [format] - 模板,默认是 YYYY-MM-DD HH:mm:ss,模板字符:
121
- * - YYYY:年
122
- * - yyyy: 年
123
- * - MM:月
124
- * - DD:日
125
- * - dd: 日
126
- * - HH:时(24 小时制)
127
- * - mm:分
128
- * - ss:秒
129
- * - SSS:毫秒
130
- * - ww: 周
121
+ * - YYYY/yyyy:年
122
+ * - MM:月(补零)
123
+ * - M:月(不补零)
124
+ * - DD/dd:日(补零)
125
+ * - D/d:日(不补零)
126
+ * - HH:时(24 小时制,补零)
127
+ * - H:时(24 小时制,不补零)
128
+ * - mm:分(补零)
129
+ * - m:分(不补零)
130
+ * - ss:秒(补零)
131
+ * - s:秒(不补零)
132
+ * - SSS:毫秒(3 位)
133
+ * - SS:毫秒(2 位)
134
+ * - S:毫秒(1 位)
135
+ * - ww:中文完整星期(如:周日)
136
+ * - w:中文星期(如:周日)
131
137
  * @returns {string} 格式化后的日期字符串
132
138
  */
133
139
  function formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
@@ -156,61 +162,113 @@ function formatDate(value, format = 'YYYY-MM-DD HH:mm:ss') {
156
162
  return fmt;
157
163
  }
158
164
  /**
159
- * 计算向前或向后N天的具体日期
160
- * @param {DateValue} originDate - 参考日期
161
- * @param {number} n - 正数:向后推算;负数:向前推算
162
- * @param {string} sep - 日期格式的分隔符
163
- * @returns {string} 计算后的目标日期
165
+ * 调整日期(增加或减少特定时间单位)
166
+ * @param {DateValue} originDate - 参考日期,可以是 Date 对象、时间戳或日期字符串
167
+ * @param {CalculateDateOptions} options - 配置项,支持多种时间单位
168
+ * @returns {string | Date} 计算后的日期/日期时间字符串或 Date 对象
169
+ * @example
170
+ * // 基础用法(向后 2 天)
171
+ * adjustDate('2024-01-01', { days: 2 }) // '2024-01-03'
172
+ *
173
+ * // 向前 2 天
174
+ * adjustDate('2024-01-01', { days: -2 }) // '2023-12-30'
175
+ *
176
+ * // 向后 1 年 2 个月 3 天
177
+ * adjustDate('2024-01-01', { years: 1, months: 2, days: 3 }) // '2025-03-04'
178
+ *
179
+ * // 向后 2 周
180
+ * adjustDate('2024-01-01', { weeks: 2 }) // '2024-01-15'
181
+ *
182
+ * // 包含时间(向后 2 天 3 小时 30 分钟)
183
+ * adjustDate('2024-01-01 10:30:00', { days: 2, hours: 3, minutes: 30 }) // '2024-01-03 14:00'
184
+ *
185
+ * // 自定义格式
186
+ * adjustDate('2024-01-01', { days: 2, format: 'YYYY/MM/DD' }) // '2024/01/03'
187
+ * adjustDate('2024-01-01', { days: 2, format: 'YYYY 年 MM 月 DD 日' }) // '2024 年 01 月 03 日'
188
+ *
189
+ * // 时间戳输入
190
+ * adjustDate(1717330884896, { days: 2 }) // '2024-06-04'
191
+ *
192
+ * // 精确到毫秒
193
+ * adjustDate('2024-01-01 10:30:00', { hours: 1, minutes: 30, seconds: 45, milliseconds: 500 })
194
+ *
195
+ * // 返回 Date 对象
196
+ * adjustDate('2024-01-01', { days: 2, returnDate: true }) // Date 对象
164
197
  */
165
- function calculateDate(originDate, n, sep = '-') {
166
- //originDate 为字符串日期 如:'2019-01-01' n为你要传入的参数,当前为0,前一天为-1,后一天为1
167
- const date = new Date(originDate); //这边给定一个特定时间
168
- const newDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
169
- const millisecondGap = newDate.getTime() + 1000 * 60 * 60 * 24 * parseInt(String(n)); //计算前几天用减,计算后几天用加,最后一个就是多少天的数量
170
- const targetDate = new Date(millisecondGap);
171
- const finalNewDate =
172
- targetDate.getFullYear() +
173
- sep +
174
- String(targetDate.getMonth() + 1).padStart(2, '0') +
175
- '-' +
176
- String(targetDate.getDate()).padStart(2, '0');
177
- return finalNewDate;
178
- }
179
- /**
180
- * 计算向前或向后N天的具体日期时间
181
- * @param {DateValue} originDateTime - 参考日期时间
182
- * @param {number} n - 正数:向后推算;负数:向前推算
183
- * @param {string} dateSep - 日期分隔符
184
- * @param {string} timeSep - 时间分隔符
185
- * @returns {string} 转换后的目标日期时间
186
- */
187
- function calculateDateTime(originDateTime, n, dateSep = '-', timeSep = ':') {
188
- const date = new Date(originDateTime);
189
- const separator1 = dateSep;
190
- const separator2 = timeSep;
191
- const dateTime = new Date(
192
- date.getFullYear(),
193
- date.getMonth(),
194
- date.getDate(),
195
- date.getHours(),
196
- date.getMinutes(),
197
- date.getSeconds()
198
- );
199
- const millisecondGap = dateTime.getTime() + 1000 * 60 * 60 * 24 * parseInt(String(n)); //计算前几天用减,计算后几天用加,最后一个就是多少天的数量
200
- const targetDateTime = new Date(millisecondGap);
201
- return (
202
- targetDateTime.getFullYear() +
203
- separator1 +
204
- String(targetDateTime.getMonth() + 1).padStart(2, '0') +
205
- separator1 +
206
- String(targetDateTime.getDate()).padStart(2, '0') +
207
- ' ' +
208
- String(targetDateTime.getHours()).padStart(2, '0') +
209
- separator2 +
210
- String(targetDateTime.getMinutes()).padStart(2, '0') +
211
- separator2 +
212
- String(targetDateTime.getSeconds()).padStart(2, '0')
213
- );
198
+ function adjustDate(originDate, options = {}) {
199
+ const {
200
+ format,
201
+ returnDate = false,
202
+ years = 0,
203
+ months = 0,
204
+ weeks = 0,
205
+ days = 0,
206
+ hours = 0,
207
+ minutes = 0,
208
+ seconds = 0,
209
+ milliseconds = 0
210
+ } = options;
211
+ const date = dateParse(originDate);
212
+ const targetDate = new Date(date);
213
+ // 保存原始日期以便处理月末边界
214
+ const originalDay = date.getDate();
215
+ const originalMonthDays = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
216
+ const isEndOfMonth = originalDay === originalMonthDays;
217
+ targetDate.setFullYear(targetDate.getFullYear() + years);
218
+ // 处理月末边界:如果原始日期是月末,需要特殊处理
219
+ if (months !== 0) {
220
+ const targetMonthIndex = targetDate.getMonth() + months;
221
+ const targetMonthDays = new Date(targetDate.getFullYear(), targetMonthIndex + 1, 0).getDate();
222
+ // 先将日期设为 1 号,避免 setMonth 时因日期过大而自动进位
223
+ targetDate.setDate(1);
224
+ targetDate.setMonth(targetMonthIndex);
225
+ // 如果原始日期是月末,则调整为目标月份的月末
226
+ if (isEndOfMonth) {
227
+ targetDate.setDate(targetMonthDays);
228
+ } else if (originalDay > targetMonthDays) {
229
+ // 如果原始日期大于目标月份的最大天数,也调整为目标月份的月末
230
+ targetDate.setDate(targetMonthDays);
231
+ } else {
232
+ // 否则保持原始日期
233
+ targetDate.setDate(originalDay);
234
+ }
235
+ }
236
+ // 处理天数(不包括月份变化)
237
+ if (days !== 0 || weeks !== 0) {
238
+ targetDate.setDate(targetDate.getDate() + days + weeks * 7);
239
+ }
240
+ targetDate.setHours(targetDate.getHours() + hours);
241
+ targetDate.setMinutes(targetDate.getMinutes() + minutes);
242
+ targetDate.setSeconds(targetDate.getSeconds() + seconds);
243
+ targetDate.setMilliseconds(targetDate.getMilliseconds() + milliseconds);
244
+ if (returnDate) {
245
+ return targetDate;
246
+ }
247
+ if (format) {
248
+ return formatDate(targetDate, format);
249
+ }
250
+ const year = targetDate.getFullYear();
251
+ const month = String(targetDate.getMonth() + 1).padStart(2, '0');
252
+ const day = String(targetDate.getDate()).padStart(2, '0');
253
+ const hoursStr = String(targetDate.getHours()).padStart(2, '0');
254
+ const minutesStr = String(targetDate.getMinutes()).padStart(2, '0');
255
+ const secondsStr = String(targetDate.getSeconds()).padStart(2, '0');
256
+ const hasTimeParam =
257
+ options.hasOwnProperty('hours') ||
258
+ options.hasOwnProperty('minutes') ||
259
+ options.hasOwnProperty('seconds') ||
260
+ options.hasOwnProperty('milliseconds');
261
+ if (hasTimeParam) {
262
+ if (options.hasOwnProperty('milliseconds')) {
263
+ const msStr = String(targetDate.getMilliseconds()).padStart(3, '0');
264
+ return `${year}-${month}-${day} ${hoursStr}:${minutesStr}:${secondsStr}.${msStr}`;
265
+ }
266
+ if (options.hasOwnProperty('seconds')) {
267
+ return `${year}-${month}-${day} ${hoursStr}:${minutesStr}:${secondsStr}`;
268
+ }
269
+ return `${year}-${month}-${day} ${hoursStr}:${minutesStr}`;
270
+ }
271
+ return `${year}-${month}-${day}`;
214
272
  }
215
273
  var date = {
216
274
  isValidDate,
@@ -218,12 +276,14 @@ var date = {
218
276
  dateToStart,
219
277
  dateToEnd,
220
278
  formatDate,
221
- calculateDate,
222
- calculateDateTime
279
+ adjustDate,
280
+ /**
281
+ * @deprecated 已废弃,请使用 adjustDate
282
+ */
283
+ calculateDate: adjustDate
223
284
  };
224
285
 
225
- exports.calculateDate = calculateDate;
226
- exports.calculateDateTime = calculateDateTime;
286
+ exports.adjustDate = adjustDate;
227
287
  exports.dateParse = dateParse;
228
288
  exports.dateToEnd = dateToEnd;
229
289
  exports.dateToStart = dateToStart;
package/dist/cjs/dom.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
package/dist/cjs/file.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
package/dist/cjs/func.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -79,8 +79,7 @@ exports.fallbackCopyText = clipboard.fallbackCopyText;
79
79
  exports.cookieDel = cookie.cookieDel;
80
80
  exports.cookieGet = cookie.cookieGet;
81
81
  exports.cookieSet = cookie.cookieSet;
82
- exports.calculateDate = date.calculateDate;
83
- exports.calculateDateTime = date.calculateDateTime;
82
+ exports.adjustDate = date.adjustDate;
84
83
  exports.dateParse = date.dateParse;
85
84
  exports.dateToEnd = date.dateToEnd;
86
85
  exports.dateToStart = date.dateToStart;
@@ -124,14 +123,20 @@ exports.stringFill = string.stringFill;
124
123
  exports.stringFormat = string.stringFormat;
125
124
  exports.stringKebabCase = string.stringKebabCase;
126
125
  exports.arrayLike = type.arrayLike;
126
+ exports.is = type.is;
127
+ exports.isArguments = type.isArguments;
127
128
  exports.isArray = type.isArray;
129
+ exports.isArrayBuffer = type.isArrayBuffer;
130
+ exports.isAsyncFunction = type.isAsyncFunction;
128
131
  exports.isBigInt = type.isBigInt;
129
132
  exports.isBoolean = type.isBoolean;
133
+ exports.isDataView = type.isDataView;
130
134
  exports.isDate = type.isDate;
131
135
  exports.isEmpty = type.isEmpty;
132
136
  exports.isError = type.isError;
133
137
  exports.isFunction = type.isFunction;
134
138
  exports.isJsonString = type.isJsonString;
139
+ exports.isMap = type.isMap;
135
140
  exports.isNaN = type.isNaN;
136
141
  exports.isNodeList = type.isNodeList;
137
142
  exports.isNull = type.isNull;
@@ -140,9 +145,12 @@ exports.isNullish = type.isNullOrUnDef;
140
145
  exports.isNumber = type.isNumber;
141
146
  exports.isObject = type.isObject;
142
147
  exports.isPrimitive = type.isPrimitive;
148
+ exports.isPromise = type.isPromise;
143
149
  exports.isRegExp = type.isRegExp;
150
+ exports.isSet = type.isSet;
144
151
  exports.isString = type.isString;
145
152
  exports.isSymbol = type.isSymbol;
153
+ exports.isTypedArray = type.isTypedArray;
146
154
  exports.isUndefined = type.isUndefined;
147
155
  exports.objectHas = type.objectHas;
148
156
  exports.typeIs = type.typeIs;
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
package/dist/cjs/math.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */
package/dist/cjs/path.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * sculp-js v1.19.1
2
+ * sculp-js v1.19.3
3
3
  * (c) 2023-present chandq
4
4
  * Released under the MIT License.
5
5
  */