atomic-fns 1.1.6 → 1.2.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/README.md +51 -12
- package/dist/collections/BTree.d.ts +11 -10
- package/dist/collections/BTree.js +58 -80
- package/dist/collections/Heap.d.ts +2 -2
- package/dist/collections/Heap.js +1 -1
- package/dist/collections/LRUCache.d.ts +8 -5
- package/dist/collections/LRUCache.js +24 -11
- package/dist/collections/SortedMap.d.ts +4 -4
- package/dist/collections/SortedMap.js +4 -3
- package/dist/collections/SortedSet.d.ts +2 -2
- package/dist/collections/SortedTree.d.ts +9 -9
- package/dist/collections/SortedTree.js +7 -6
- package/dist/collections/SplayTree.d.ts +17 -15
- package/dist/collections/SplayTree.js +42 -29
- package/dist/collections/Trie.d.ts +2 -2
- package/dist/collections/Trie.js +26 -26
- package/dist/collections/deque.d.ts +11 -11
- package/dist/collections/deque.js +17 -10
- package/dist/collections/frozenset.js +4 -1
- package/dist/collections/index.d.ts +30 -48
- package/dist/collections/index.js +210 -82
- package/dist/decimal/index.d.ts +7 -5
- package/dist/decimal/index.js +63 -28
- package/dist/functools/index.d.ts +10 -34
- package/dist/functools/index.js +25 -57
- package/dist/globals/index.d.ts +5 -22
- package/dist/globals/index.js +24 -40
- package/dist/i18n/currency.d.ts +10 -7
- package/dist/i18n/currency.js +22 -7
- package/dist/i18n/date/index.d.ts +22 -16
- package/dist/i18n/date/index.js +89 -67
- package/dist/i18n/date/utils.d.ts +6 -7
- package/dist/i18n/date/utils.js +15 -113
- package/dist/i18n/duration.d.ts +13 -12
- package/dist/i18n/duration.js +38 -32
- package/dist/i18n/format.d.ts +10 -2
- package/dist/i18n/format.js +100 -217
- package/dist/i18n/index.d.ts +2 -1
- package/dist/itertools/index.d.ts +21 -25
- package/dist/itertools/index.js +41 -44
- package/dist/math/index.d.ts +12 -29
- package/dist/math/index.js +16 -33
- package/dist/mod.d.ts +1 -0
- package/dist/mod.js +1 -0
- package/dist/operators/index.d.ts +3 -3
- package/dist/operators/index.js +62 -38
- package/dist/random/index.js +9 -6
- package/dist/string/index.d.ts +1 -1
- package/dist/string/index.js +2 -4
- package/dist/types.d.ts +3 -3
- package/package.json +16 -21
package/dist/globals/index.js
CHANGED
|
@@ -18,13 +18,16 @@ export class CustomError extends Error {
|
|
|
18
18
|
/**
|
|
19
19
|
* Returns a new CustomError with the specified message.
|
|
20
20
|
* @param {string} message
|
|
21
|
+
* @param {ErrorOptions} [options] Standard error options such as `cause`.
|
|
21
22
|
* @constructor
|
|
22
23
|
*/
|
|
23
|
-
constructor(message) {
|
|
24
|
-
super(message);
|
|
24
|
+
constructor(message, options) {
|
|
25
|
+
super(message, options);
|
|
25
26
|
this.name = this.constructor.name;
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
// V8 and Bun have it, and only Node's types declare it, which JSR's type check does not load
|
|
28
|
+
const errorType = Error;
|
|
29
|
+
if (typeof errorType.captureStackTrace === 'function') {
|
|
30
|
+
errorType.captureStackTrace(this, this.constructor);
|
|
28
31
|
}
|
|
29
32
|
else {
|
|
30
33
|
this.stack = new Error(message).stack;
|
|
@@ -90,7 +93,7 @@ export function type(value) {
|
|
|
90
93
|
return 'error';
|
|
91
94
|
if (value[Symbol.toStringTag])
|
|
92
95
|
return value[Symbol.toStringTag];
|
|
93
|
-
const className =
|
|
96
|
+
const className = Object.prototype.toString.call(value);
|
|
94
97
|
if (className === '[object Window]')
|
|
95
98
|
return 'object';
|
|
96
99
|
if (className.endsWith('Array]') || Array.isArray(value)) {
|
|
@@ -150,10 +153,6 @@ export function isObject(x) {
|
|
|
150
153
|
export function isString(x) {
|
|
151
154
|
return type(x) === 'string';
|
|
152
155
|
}
|
|
153
|
-
/** Check if value is an Array type. */
|
|
154
|
-
export function isArray(x) {
|
|
155
|
-
return Array.isArray(x);
|
|
156
|
-
}
|
|
157
156
|
/**
|
|
158
157
|
* Check if value is Array-like type.
|
|
159
158
|
* A value is considered array-like if it's not a function and has a `.length` number property.
|
|
@@ -166,10 +165,6 @@ export function isArrayLike(x) {
|
|
|
166
165
|
export function isNumber(x) {
|
|
167
166
|
return type(x) === 'number';
|
|
168
167
|
}
|
|
169
|
-
/** Check if value is an integer number type. */
|
|
170
|
-
export function isInteger(x) {
|
|
171
|
-
return type(x) === 'number' && Math.trunc(x) === x;
|
|
172
|
-
}
|
|
173
168
|
/** Check if value is a bigint type. */
|
|
174
169
|
export function isBigint(x) {
|
|
175
170
|
return type(x) === 'bigint';
|
|
@@ -180,15 +175,15 @@ export function isPromise(x) {
|
|
|
180
175
|
}
|
|
181
176
|
/** Check if value is a function type. */
|
|
182
177
|
export function isFunction(x) {
|
|
183
|
-
return x
|
|
178
|
+
return typeof x === 'function';
|
|
184
179
|
}
|
|
185
180
|
/** Check if value is an async function type. */
|
|
186
181
|
export function isAsyncFunction(x) {
|
|
187
|
-
return x?.constructor
|
|
182
|
+
return x?.constructor?.name === 'AsyncFunction';
|
|
188
183
|
}
|
|
189
184
|
/** Check if value is a generator function type. */
|
|
190
185
|
export function isGenerator(x) {
|
|
191
|
-
return x?.constructor
|
|
186
|
+
return x?.constructor?.constructor?.name === 'GeneratorFunction';
|
|
192
187
|
}
|
|
193
188
|
/** Check if value is `null` or `undefined`. */
|
|
194
189
|
export function isNull(x) {
|
|
@@ -282,7 +277,7 @@ uuid()
|
|
|
282
277
|
*/
|
|
283
278
|
export function uuid() {
|
|
284
279
|
const u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
|
|
285
|
-
return [u.
|
|
280
|
+
return [u.slice(0, 8), u.slice(8, 12), `4000-8${u.slice(13, 16)}`, u.slice(16, 28)].join('-');
|
|
286
281
|
}
|
|
287
282
|
/**
|
|
288
283
|
* Checks if `obj.key` is a function, and calls it with any given `args`.
|
|
@@ -292,7 +287,7 @@ export function uuid() {
|
|
|
292
287
|
* @return `obj.key(...args)` or `undefined`.
|
|
293
288
|
*/
|
|
294
289
|
export function call(obj, key, ...args) {
|
|
295
|
-
if (isFunction(get(key, obj))) {
|
|
290
|
+
if (isFunction(get([key], obj))) {
|
|
296
291
|
return obj[key](...args);
|
|
297
292
|
}
|
|
298
293
|
}
|
|
@@ -302,25 +297,7 @@ export function chr(x) {
|
|
|
302
297
|
}
|
|
303
298
|
/** Convert character to Unicode code point */
|
|
304
299
|
export function ord(x) {
|
|
305
|
-
return x.
|
|
306
|
-
}
|
|
307
|
-
/**
|
|
308
|
-
* Returns an array of the own enumerable property names of `object`.
|
|
309
|
-
* @param object The given object.
|
|
310
|
-
* @returns The array of object keys.
|
|
311
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys Object.keys()}
|
|
312
|
-
*/
|
|
313
|
-
export function keys(object) {
|
|
314
|
-
return Object.keys(object);
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Returns an array of the own enumerable property values of `object`.
|
|
318
|
-
* @param object The given object.
|
|
319
|
-
* @returns The array of object keys.
|
|
320
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values Object.values()}
|
|
321
|
-
*/
|
|
322
|
-
export function values(object) {
|
|
323
|
-
return Object.values(object);
|
|
300
|
+
return x.codePointAt(0) ?? Number.NaN;
|
|
324
301
|
}
|
|
325
302
|
/**
|
|
326
303
|
* Check if a given property is present in a given object.
|
|
@@ -329,7 +306,7 @@ export function values(object) {
|
|
|
329
306
|
* @returns `true` if the object has the property name.
|
|
330
307
|
*/
|
|
331
308
|
export function has(obj, attr) {
|
|
332
|
-
return obj && attr in obj;
|
|
309
|
+
return obj != null && attr in Object(obj);
|
|
333
310
|
}
|
|
334
311
|
export function get(key, obj, value) {
|
|
335
312
|
if (obj == null)
|
|
@@ -372,19 +349,26 @@ export function del(attr, x) {
|
|
|
372
349
|
export function set(attr, obj, value, writable = false, enumerable = false) {
|
|
373
350
|
return Object.defineProperty(obj, attr, {
|
|
374
351
|
value,
|
|
352
|
+
configurable: true,
|
|
375
353
|
enumerable,
|
|
376
354
|
writable
|
|
377
355
|
});
|
|
378
356
|
}
|
|
379
357
|
export const HASH_KEY = Symbol.for('HASH_KEY');
|
|
358
|
+
const sealedHashes = new WeakMap();
|
|
380
359
|
export function hash(obj) {
|
|
381
360
|
if (typeof obj === 'string') {
|
|
382
361
|
return hashCode(obj);
|
|
383
362
|
}
|
|
384
|
-
if (typeof obj === 'object') {
|
|
385
|
-
if (get(HASH_KEY, obj)
|
|
363
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
364
|
+
if (get(HASH_KEY, obj) != null) {
|
|
386
365
|
return obj[HASH_KEY];
|
|
387
366
|
}
|
|
367
|
+
if (!Object.isExtensible(obj)) {
|
|
368
|
+
if (!sealedHashes.has(obj))
|
|
369
|
+
sealedHashes.set(obj, uniqueId());
|
|
370
|
+
return sealedHashes.get(obj);
|
|
371
|
+
}
|
|
388
372
|
obj[HASH_KEY] = uniqueId();
|
|
389
373
|
return obj[HASH_KEY];
|
|
390
374
|
}
|
package/dist/i18n/currency.d.ts
CHANGED
|
@@ -6,19 +6,22 @@ export declare class Currency extends Decimal {
|
|
|
6
6
|
private readonly locale;
|
|
7
7
|
private readonly currency;
|
|
8
8
|
private readonly numberFormat;
|
|
9
|
+
private readonly overrides;
|
|
9
10
|
private readonly options;
|
|
10
11
|
constructor(amount: any, currency: string, locale?: string, opts?: Intl.NumberFormatOptions);
|
|
11
|
-
clone(n:
|
|
12
|
+
clone(n: Currency): Currency;
|
|
12
13
|
negated(): Currency;
|
|
13
|
-
add(x:
|
|
14
|
-
sub(x:
|
|
15
|
-
div(x:
|
|
16
|
-
mul(x:
|
|
17
|
-
toDecimal():
|
|
14
|
+
add(x: Currency | string): Currency;
|
|
15
|
+
sub(x: Currency | string): Currency;
|
|
16
|
+
div(x: Currency | Decimal | string | number): Currency;
|
|
17
|
+
mul(x: Currency | Decimal): Currency;
|
|
18
|
+
toDecimal(): Decimal;
|
|
19
|
+
/** `Intl` reads a decimal string exactly, while a `Number` past 2^53 has lost digits. */
|
|
20
|
+
private formattable;
|
|
18
21
|
toString(): string;
|
|
19
22
|
format(opts?: Intl.NumberFormatOptions, locale?: string): string;
|
|
20
23
|
displayName(): string;
|
|
21
24
|
accounting(): string;
|
|
22
25
|
precision(digits?: number): string;
|
|
23
|
-
eq(x: any):
|
|
26
|
+
eq(x: any): boolean;
|
|
24
27
|
}
|
package/dist/i18n/currency.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { defaults } from '../collections/index.js';
|
|
2
2
|
import { isObject } from '../globals/index.js';
|
|
3
3
|
import { Decimal } from '../decimal/index.js';
|
|
4
|
+
/** `Intl` options that set the digits shown. Some reject each other, so they replace as a group. */
|
|
5
|
+
const DIGIT_OPTION = /^(minimum|maximum)(Fraction|Significant)Digits$|^rounding(Increment|Priority)$/;
|
|
4
6
|
/**
|
|
5
7
|
* Currency represents a local currency amount that can be formatted using the `Intl` apis.
|
|
6
8
|
*/
|
|
@@ -8,6 +10,7 @@ export class Currency extends Decimal {
|
|
|
8
10
|
locale;
|
|
9
11
|
currency;
|
|
10
12
|
numberFormat;
|
|
13
|
+
overrides;
|
|
11
14
|
options = {
|
|
12
15
|
style: 'currency',
|
|
13
16
|
currencyDisplay: 'symbol',
|
|
@@ -19,16 +22,17 @@ export class Currency extends Decimal {
|
|
|
19
22
|
opts = locale;
|
|
20
23
|
locale = undefined;
|
|
21
24
|
}
|
|
22
|
-
const systemLocale = new Intl.NumberFormat(locale, defaults(opts, { currency }, this.options));
|
|
25
|
+
const systemLocale = new Intl.NumberFormat(locale, defaults({}, opts, { currency }, this.options));
|
|
23
26
|
const resolved = systemLocale.resolvedOptions();
|
|
24
27
|
this.numberFormat = systemLocale;
|
|
25
28
|
this.options.currency = currency;
|
|
29
|
+
this.overrides = defaults({}, opts);
|
|
26
30
|
this.currency = resolved.currency;
|
|
27
31
|
this.locale = resolved.locale;
|
|
28
32
|
}
|
|
29
33
|
// @ts-expect-error overrides
|
|
30
34
|
clone(n) {
|
|
31
|
-
return new Currency(n, this.currency, this.locale, this.
|
|
35
|
+
return new Currency(n === undefined ? this : n, this.currency, this.locale, this.overrides);
|
|
32
36
|
}
|
|
33
37
|
// @ts-expect-error overrides
|
|
34
38
|
negated() {
|
|
@@ -58,14 +62,25 @@ export class Currency extends Decimal {
|
|
|
58
62
|
toDecimal() {
|
|
59
63
|
return super.clone.call(this);
|
|
60
64
|
}
|
|
61
|
-
|
|
65
|
+
/** `Intl` reads a decimal string exactly, while a `Number` past 2^53 has lost digits. */
|
|
66
|
+
formattable() {
|
|
62
67
|
const number = this.toNumber();
|
|
63
|
-
|
|
68
|
+
if (Math.abs(number) <= Number.MAX_SAFE_INTEGER)
|
|
69
|
+
return number;
|
|
70
|
+
return Decimal.prototype.toString.call(this);
|
|
71
|
+
}
|
|
72
|
+
toString() {
|
|
73
|
+
return this.numberFormat.format(this.formattable());
|
|
64
74
|
}
|
|
65
75
|
format(opts = {}, locale) {
|
|
66
|
-
const
|
|
67
|
-
opts
|
|
68
|
-
|
|
76
|
+
const overrides = { ...this.overrides };
|
|
77
|
+
if (Object.keys(opts).some((key) => DIGIT_OPTION.test(key) && opts[key] !== undefined)) {
|
|
78
|
+
for (const key in overrides)
|
|
79
|
+
if (DIGIT_OPTION.test(key))
|
|
80
|
+
delete overrides[key];
|
|
81
|
+
}
|
|
82
|
+
opts = defaults({}, opts, overrides, this.options);
|
|
83
|
+
return new Intl.NumberFormat(locale ?? this.locale, opts).format(this.formattable());
|
|
69
84
|
}
|
|
70
85
|
displayName() {
|
|
71
86
|
return this.format({ currencyDisplay: 'name' });
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { Duration, DurationUnit, TDuration } from '../duration.js';
|
|
1
|
+
import { Duration, type DurationUnit, type TDuration } from '../duration.js';
|
|
2
2
|
import { asDate, formatDate, strftime } from '../format.js';
|
|
3
|
-
import { DateObject, daysInMonth, daysInYear, isLeapYear, maxDate, minDate, weeksInYear } from './utils.js';
|
|
3
|
+
import { type DateObject, daysInMonth, daysInYear, isLeapYear, maxDate, minDate, weeksInYear } from './utils.js';
|
|
4
4
|
export { asDate, daysInMonth, daysInYear, formatDate, isLeapYear, maxDate, minDate, strftime, weeksInYear };
|
|
5
|
-
export { DateObject };
|
|
6
|
-
export
|
|
7
|
-
export declare type DateLike = DateInput | IntlDate | DateObject;
|
|
5
|
+
export type { DateObject };
|
|
6
|
+
export type DateLike = number | string | Date | IntlDate | DateObject;
|
|
8
7
|
/**
|
|
9
8
|
* Creates a date tied to a given locale (default system locale) which can be formatted in that locale's language using the native {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl Apis} directly or using a formatting string.
|
|
10
9
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl Apis}
|
|
@@ -15,7 +14,7 @@ export declare class IntlDate {
|
|
|
15
14
|
intlRelativeFormat: Intl.RelativeTimeFormat;
|
|
16
15
|
/** Parses the provided value as UTC date or returns the current UTC date. */
|
|
17
16
|
static UTC(value?: DateLike, locale?: string): IntlDate;
|
|
18
|
-
/** Returns the current local date and time
|
|
17
|
+
/** Returns the current local date and time. */
|
|
19
18
|
static now(): IntlDate;
|
|
20
19
|
/** Creates a new date from a Unix timestamp (seconds since the unix epoch) */
|
|
21
20
|
static unix(seconds: number): IntlDate;
|
|
@@ -53,14 +52,14 @@ export declare class IntlDate {
|
|
|
53
52
|
dayOfYear(): number;
|
|
54
53
|
/** Returns `true` if this date's year is a leap year. */
|
|
55
54
|
isLeapYear(): boolean;
|
|
56
|
-
/** Gets the number of weeks
|
|
55
|
+
/** Gets the number of Monday-first weeks in the current year, where week 1 is the first full week. */
|
|
57
56
|
weeksInYear(): number;
|
|
58
57
|
/** Gets the number of weeks in the current year, according to ISO weeks. */
|
|
59
58
|
isoWeeksInYear(): number;
|
|
60
59
|
/** Returns the current week of the year. */
|
|
61
|
-
week():
|
|
60
|
+
week(): number;
|
|
62
61
|
/** Returns the ISO week of the year. */
|
|
63
|
-
isoWeek():
|
|
62
|
+
isoWeek(): number;
|
|
64
63
|
/**
|
|
65
64
|
* Returns a localized string representation of this date.
|
|
66
65
|
* @param {Intl.DateTimeFormatOptions} opts The options to use for the format
|
|
@@ -129,13 +128,13 @@ export declare class IntlDate {
|
|
|
129
128
|
/** Returns the time part formatted as ISO8601.
|
|
130
129
|
* @example
|
|
131
130
|
```js
|
|
132
|
-
new IntlDate().toISOTime() // '
|
|
131
|
+
new IntlDate().toISOTime() // '22:44:30.652Z'
|
|
133
132
|
```
|
|
134
133
|
*/
|
|
135
134
|
toISOTime(): string;
|
|
136
135
|
/**
|
|
137
136
|
* Returns an object containing year, month, day-of-month, hours, minutes, seconds, milliseconds.
|
|
138
|
-
* @returns {Object} An object like `{year, month,
|
|
137
|
+
* @returns {Object} An object like `{year, month, day, hour, minute, second, millisecond}`
|
|
139
138
|
*/
|
|
140
139
|
toObject(): DateObject;
|
|
141
140
|
/** Returns the number of milliseconds since the Unix Epoch (January 1, 1970 UTC) */
|
|
@@ -186,19 +185,26 @@ export declare class IntlDate {
|
|
|
186
185
|
diff(other: DateLike, unit?: DurationUnit, exact?: boolean): number;
|
|
187
186
|
add(duration: TDuration, exact?: boolean): IntlDate;
|
|
188
187
|
subtract(duration: TDuration, exact?: boolean): IntlDate;
|
|
189
|
-
startOf(unit: DurationUnit):
|
|
190
|
-
endOf(unit: DurationUnit):
|
|
188
|
+
startOf(unit: DurationUnit): any;
|
|
189
|
+
endOf(unit: DurationUnit): any;
|
|
191
190
|
clone(date?: DateLike): IntlDate;
|
|
192
191
|
static max(...args: any[]): any;
|
|
193
192
|
static min(...args: any[]): any;
|
|
194
193
|
inspect(): string;
|
|
195
194
|
}
|
|
196
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Add the specified years, months, weeks, days, hours, minutes and seconds to the given date
|
|
197
|
+
* @param date
|
|
198
|
+
* @param duration
|
|
199
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
200
|
+
* @returns
|
|
201
|
+
*/
|
|
202
|
+
export declare function addDuration(date: number | string | Date, duration: number | Duration | TDuration, exact?: boolean): Date;
|
|
197
203
|
/**
|
|
198
204
|
* Subtract the specified years, months, weeks, days, hours, minutes and seconds from the given date.
|
|
199
205
|
* @param date
|
|
200
206
|
* @param duration
|
|
201
|
-
* @param exact
|
|
207
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
202
208
|
* @returns
|
|
203
209
|
*/
|
|
204
|
-
export declare function subDuration(date:
|
|
210
|
+
export declare function subDuration(date: number | string | Date, duration: number | Duration | TDuration, exact?: boolean): Date;
|
package/dist/i18n/date/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isObject, ValueError } from '../../globals/index.js';
|
|
2
2
|
import { Duration, UNITS_PLURAL } from '../duration.js';
|
|
3
|
-
import { asDate, formatDate, strftime } from '../format.js';
|
|
3
|
+
import { asDate, formatDate, fromFields, strftime } from '../format.js';
|
|
4
4
|
import { asNumber, dayOfYear, daysInMonth, daysInYear, isLeapYear, maxDate, minDate, weekOfYear, weeksInYear } from './utils.js';
|
|
5
5
|
// Export date functions
|
|
6
6
|
export { asDate, daysInMonth, daysInYear, formatDate, isLeapYear, maxDate, minDate, strftime, weeksInYear };
|
|
@@ -17,7 +17,7 @@ export class IntlDate {
|
|
|
17
17
|
static UTC(value, locale) {
|
|
18
18
|
return new IntlDate(value, { utc: true, locale });
|
|
19
19
|
}
|
|
20
|
-
/** Returns the current local date and time
|
|
20
|
+
/** Returns the current local date and time. */
|
|
21
21
|
static now() {
|
|
22
22
|
return new IntlDate();
|
|
23
23
|
}
|
|
@@ -45,16 +45,8 @@ export class IntlDate {
|
|
|
45
45
|
else if (isObject(obj)) {
|
|
46
46
|
let { year, month, day, hour, minute, second, millisecond } = obj;
|
|
47
47
|
// NOTE month is from 1-12, not from 0-11
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
if (utc) {
|
|
52
|
-
// from UTC to current
|
|
53
|
-
this._date = new Date(Date.UTC(year, month, day || 1, hour || 0, minute || 0, second || 0, millisecond || 0));
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
this._date = new Date(year, month, day || 1, hour || 0, minute || 0, second || 0, millisecond || 0);
|
|
57
|
-
}
|
|
48
|
+
month = (month ?? 1) - 1;
|
|
49
|
+
this._date = fromFields(utc, Number(year), month, day || 1, hour || 0, minute || 0, second || 0, millisecond || 0);
|
|
58
50
|
}
|
|
59
51
|
else {
|
|
60
52
|
this._date = asDate(obj, utc);
|
|
@@ -113,7 +105,7 @@ export class IntlDate {
|
|
|
113
105
|
isLeapYear() {
|
|
114
106
|
return isLeapYear(this.year);
|
|
115
107
|
}
|
|
116
|
-
/** Gets the number of weeks
|
|
108
|
+
/** Gets the number of Monday-first weeks in the current year, where week 1 is the first full week. */
|
|
117
109
|
weeksInYear() {
|
|
118
110
|
return weeksInYear(this.year);
|
|
119
111
|
}
|
|
@@ -208,20 +200,20 @@ export class IntlDate {
|
|
|
208
200
|
```
|
|
209
201
|
*/
|
|
210
202
|
toISODate() {
|
|
211
|
-
return this._date.toISOString().
|
|
203
|
+
return this._date.toISOString().split('T')[0];
|
|
212
204
|
}
|
|
213
205
|
/** Returns the time part formatted as ISO8601.
|
|
214
206
|
* @example
|
|
215
207
|
```js
|
|
216
|
-
new IntlDate().toISOTime() // '
|
|
208
|
+
new IntlDate().toISOTime() // '22:44:30.652Z'
|
|
217
209
|
```
|
|
218
210
|
*/
|
|
219
211
|
toISOTime() {
|
|
220
|
-
return this._date.toISOString().
|
|
212
|
+
return this._date.toISOString().split('T')[1];
|
|
221
213
|
}
|
|
222
214
|
/**
|
|
223
215
|
* Returns an object containing year, month, day-of-month, hours, minutes, seconds, milliseconds.
|
|
224
|
-
* @returns {Object} An object like `{year, month,
|
|
216
|
+
* @returns {Object} An object like `{year, month, day, hour, minute, second, millisecond}`
|
|
225
217
|
*/
|
|
226
218
|
toObject() {
|
|
227
219
|
return {
|
|
@@ -248,7 +240,10 @@ export class IntlDate {
|
|
|
248
240
|
}
|
|
249
241
|
/** Returns the timezone GMT offset as a string */
|
|
250
242
|
zone() {
|
|
251
|
-
|
|
243
|
+
if (!this.isValid())
|
|
244
|
+
return INVALID_DATE_STRING;
|
|
245
|
+
const zoneFormat = new Intl.DateTimeFormat(this.locale, { timeZoneName: 'longOffset' });
|
|
246
|
+
return zoneFormat.formatToParts(this._date).find((part) => part.type === 'timeZoneName').value;
|
|
252
247
|
}
|
|
253
248
|
/** Returns the difference in `minutes` between this date and UTC */
|
|
254
249
|
utcOffset() {
|
|
@@ -308,7 +303,7 @@ export class IntlDate {
|
|
|
308
303
|
compare(other) {
|
|
309
304
|
if (!this.isValid())
|
|
310
305
|
return 1;
|
|
311
|
-
|
|
306
|
+
const dt = new IntlDate(other);
|
|
312
307
|
if (!dt.isValid())
|
|
313
308
|
return -1;
|
|
314
309
|
return this.getTime() - dt.getTime();
|
|
@@ -317,13 +312,18 @@ export class IntlDate {
|
|
|
317
312
|
if (!this.isValid())
|
|
318
313
|
return this;
|
|
319
314
|
const normalized = normalizeObject(values, normalizeUnit);
|
|
320
|
-
|
|
315
|
+
const mixed = { ...this.toObject(), ...normalized };
|
|
321
316
|
// if we didn't set the day but we ended up on an overflow date,
|
|
322
317
|
// use the last day of the right month
|
|
323
318
|
if (normalized.day === undefined) {
|
|
324
|
-
|
|
319
|
+
const target = new Date(this._date);
|
|
320
|
+
target.setFullYear(mixed.year, mixed.month - 1, 1);
|
|
321
|
+
mixed.day = Math.min(daysInMonth(target), mixed.day);
|
|
325
322
|
}
|
|
326
|
-
|
|
323
|
+
const result = this.clone(mixed);
|
|
324
|
+
return normalized.weekday === undefined
|
|
325
|
+
? result
|
|
326
|
+
: result.add({ days: normalized.weekday - result.dayOfWeek });
|
|
327
327
|
}
|
|
328
328
|
get relativeFormat() {
|
|
329
329
|
if (this.intlRelativeFormat)
|
|
@@ -332,27 +332,42 @@ export class IntlDate {
|
|
|
332
332
|
return new Intl.RelativeTimeFormat(this.locale);
|
|
333
333
|
}
|
|
334
334
|
relativeTime(n, unit = 'seconds') {
|
|
335
|
-
return this.relativeFormat.format(n, unit);
|
|
335
|
+
return Number.isNaN(n) ? INVALID_DATE_STRING : this.relativeFormat.format(n, unit);
|
|
336
336
|
}
|
|
337
337
|
fromNow(unit = 'seconds') {
|
|
338
|
-
|
|
338
|
+
const diff = this.diff(new Date(), unit);
|
|
339
339
|
return this.relativeTime(diff, unit);
|
|
340
340
|
}
|
|
341
341
|
from(other, unit = 'seconds') {
|
|
342
|
-
|
|
342
|
+
const diff = this.diff(other, unit);
|
|
343
343
|
return this.relativeTime(diff, unit);
|
|
344
344
|
}
|
|
345
345
|
toNow(unit = 'seconds') {
|
|
346
|
-
|
|
346
|
+
const diff = this.diff(new Date(), unit);
|
|
347
347
|
return this.relativeTime(-diff, unit);
|
|
348
348
|
}
|
|
349
349
|
to(other, unit = 'seconds') {
|
|
350
|
-
|
|
350
|
+
const diff = this.diff(other, unit);
|
|
351
351
|
return this.relativeTime(-diff, unit);
|
|
352
352
|
}
|
|
353
353
|
diff(other, unit = 'milliseconds', exact = false) {
|
|
354
|
-
|
|
355
|
-
|
|
354
|
+
const dt = new IntlDate(other);
|
|
355
|
+
const normalizedUnit = UNITS_PLURAL[unit.toLowerCase()];
|
|
356
|
+
const monthsInUnit = MONTHS_IN_UNIT[normalizedUnit];
|
|
357
|
+
if (monthsInUnit && !exact) {
|
|
358
|
+
// whole months are the ones `add` can take from `other` without passing this date
|
|
359
|
+
let months = (this.year - dt.year) * 12 + this.month - dt.month;
|
|
360
|
+
const sign = Math.sign(this.getTime() - dt.getTime());
|
|
361
|
+
if (sign * (dt.add({ months }).getTime() - this.getTime()) > 0)
|
|
362
|
+
months -= sign;
|
|
363
|
+
return Math.trunc(months / monthsInUnit);
|
|
364
|
+
}
|
|
365
|
+
let elapsed = this.getTime() - dt.getTime();
|
|
366
|
+
if (normalizedUnit === 'days' || normalizedUnit === 'weeks') {
|
|
367
|
+
// a calendar day can last 23 or 25 hours, so measure it on the wall clock
|
|
368
|
+
elapsed += (dt._date.getTimezoneOffset() - this._date.getTimezoneOffset()) * 6e4;
|
|
369
|
+
}
|
|
370
|
+
const dur = new Duration(elapsed, exact);
|
|
356
371
|
let total = dur.total(unit);
|
|
357
372
|
if (!exact)
|
|
358
373
|
total = Math.trunc(total);
|
|
@@ -367,7 +382,8 @@ export class IntlDate {
|
|
|
367
382
|
startOf(unit) {
|
|
368
383
|
if (!this.isValid())
|
|
369
384
|
return this;
|
|
370
|
-
const obj = {}
|
|
385
|
+
const obj = {};
|
|
386
|
+
const normalizedUnit = UNITS_PLURAL[unit.toLowerCase()];
|
|
371
387
|
switch (normalizedUnit) {
|
|
372
388
|
case 'years':
|
|
373
389
|
obj.month = 1;
|
|
@@ -391,16 +407,22 @@ export class IntlDate {
|
|
|
391
407
|
break;
|
|
392
408
|
case 'milliseconds':
|
|
393
409
|
break;
|
|
394
|
-
// no default,
|
|
410
|
+
// no default, an unknown unit changes nothing
|
|
395
411
|
}
|
|
396
412
|
if (normalizedUnit === 'weeks') {
|
|
397
|
-
|
|
413
|
+
return this.subtract({ days: this.dayOfWeek - 1 }).startOf('days');
|
|
398
414
|
}
|
|
399
415
|
if (normalizedUnit === 'quarters') {
|
|
400
416
|
const q = Math.ceil(this.month / 3);
|
|
401
417
|
obj.month = (q - 1) * 3 + 1;
|
|
402
418
|
}
|
|
403
|
-
|
|
419
|
+
const start = this.set(obj);
|
|
420
|
+
if (obj.hour !== undefined)
|
|
421
|
+
return start;
|
|
422
|
+
// Date reads a repeated wall clock as its first pass, this date may be on the second
|
|
423
|
+
const offset = this._date.getTimezoneOffset();
|
|
424
|
+
const kept = new Date(start.getTime() + (offset - start._date.getTimezoneOffset()) * 6e4);
|
|
425
|
+
return kept.getTimezoneOffset() === offset ? this.clone(kept) : start;
|
|
404
426
|
}
|
|
405
427
|
endOf(unit) {
|
|
406
428
|
return this.isValid()
|
|
@@ -419,57 +441,56 @@ export class IntlDate {
|
|
|
419
441
|
return minDate.apply(undefined, args);
|
|
420
442
|
}
|
|
421
443
|
inspect() {
|
|
422
|
-
return `new IntlDate("${this.toISOString()}")
|
|
444
|
+
return this.isValid() ? `new IntlDate("${this.toISOString()}")` : 'new IntlDate(NaN)';
|
|
423
445
|
}
|
|
424
446
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
return new Date(+endDate + postoffset);
|
|
433
|
-
}
|
|
447
|
+
/**
|
|
448
|
+
* Add the specified years, months, weeks, days, hours, minutes and seconds to the given date
|
|
449
|
+
* @param date
|
|
450
|
+
* @param duration
|
|
451
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
452
|
+
* @returns
|
|
453
|
+
*/
|
|
434
454
|
export function addDuration(date, duration, exact = false) {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
455
|
+
const newDate = asDate(date);
|
|
456
|
+
const { values } = new Duration(duration, exact);
|
|
457
|
+
const { years = 0, quarters = 0, months = 0, weeks = 0, days = 0 } = values;
|
|
458
|
+
// largest unit first and all the months in one step, so a clamped day cannot carry over
|
|
459
|
+
setDateUnit(newDate, 'months', Math.trunc(years * 12 + quarters * 3 + Number(months)));
|
|
460
|
+
setDateUnit(newDate, 'days', Math.trunc(weeks * 7 + Number(days)));
|
|
461
|
+
for (const unit of ['hours', 'minutes', 'seconds', 'milliseconds']) {
|
|
462
|
+
setDateUnit(newDate, unit, Number(values[unit] ?? 0));
|
|
463
|
+
}
|
|
464
|
+
return newDate;
|
|
465
|
+
}
|
|
466
|
+
function addMonths(date, months) {
|
|
467
|
+
const target = new Date(date);
|
|
468
|
+
target.setFullYear(date.getFullYear(), date.getMonth() + months, 1);
|
|
469
|
+
const day = Math.min(date.getDate(), daysInMonth(target));
|
|
470
|
+
date.setFullYear(target.getFullYear(), target.getMonth(), day);
|
|
444
471
|
}
|
|
445
472
|
function setDateUnit(date, unit, value) {
|
|
473
|
+
// writing a date field again would move a repeated hour to its first pass
|
|
474
|
+
if (value === 0)
|
|
475
|
+
return date;
|
|
446
476
|
switch (unit) {
|
|
447
|
-
case 'years':
|
|
448
|
-
date.setFullYear(date.getFullYear() + value);
|
|
449
|
-
break;
|
|
450
|
-
case 'quarters':
|
|
451
|
-
date.setMonth(date.getMonth() + value * 3);
|
|
452
|
-
break;
|
|
453
477
|
case 'months':
|
|
454
|
-
|
|
455
|
-
break;
|
|
456
|
-
case 'weeks':
|
|
457
|
-
date.setDate(date.getDate() + value * 7);
|
|
478
|
+
addMonths(date, value);
|
|
458
479
|
break;
|
|
459
480
|
case 'days':
|
|
460
481
|
date.setDate(date.getDate() + value);
|
|
461
482
|
break;
|
|
462
483
|
case 'hours':
|
|
463
|
-
date.
|
|
484
|
+
date.setTime(date.getTime() + value * 36e5);
|
|
464
485
|
break;
|
|
465
486
|
case 'minutes':
|
|
466
|
-
date.
|
|
487
|
+
date.setTime(date.getTime() + value * 6e4);
|
|
467
488
|
break;
|
|
468
489
|
case 'seconds':
|
|
469
|
-
date.
|
|
490
|
+
date.setTime(date.getTime() + value * 1e3);
|
|
470
491
|
break;
|
|
471
492
|
case 'milliseconds':
|
|
472
|
-
date.
|
|
493
|
+
date.setTime(date.getTime() + value);
|
|
473
494
|
break;
|
|
474
495
|
default:
|
|
475
496
|
break;
|
|
@@ -480,12 +501,13 @@ function setDateUnit(date, unit, value) {
|
|
|
480
501
|
* Subtract the specified years, months, weeks, days, hours, minutes and seconds from the given date.
|
|
481
502
|
* @param date
|
|
482
503
|
* @param duration
|
|
483
|
-
* @param exact
|
|
504
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
484
505
|
* @returns
|
|
485
506
|
*/
|
|
486
507
|
export function subDuration(date, duration, exact = false) {
|
|
487
508
|
return addDuration(date, new Duration(duration, exact).negated(), exact);
|
|
488
509
|
}
|
|
510
|
+
const MONTHS_IN_UNIT = { years: 12, quarters: 3, months: 1 };
|
|
489
511
|
const UNITS_SINGULAR = {
|
|
490
512
|
year: 'year',
|
|
491
513
|
years: 'year',
|