atomic-fns 1.1.7 → 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.js +1 -1
- package/dist/collections/LRUCache.d.ts +6 -3
- package/dist/collections/LRUCache.js +24 -11
- package/dist/collections/SortedMap.js +2 -2
- package/dist/collections/SortedTree.d.ts +2 -2
- package/dist/collections/SortedTree.js +3 -2
- package/dist/collections/SplayTree.d.ts +7 -5
- package/dist/collections/SplayTree.js +39 -26
- package/dist/collections/Trie.d.ts +1 -1
- package/dist/collections/Trie.js +26 -26
- package/dist/collections/deque.d.ts +1 -1
- package/dist/collections/deque.js +17 -10
- package/dist/collections/frozenset.js +4 -1
- package/dist/collections/index.d.ts +13 -32
- package/dist/collections/index.js +210 -82
- package/dist/decimal/index.d.ts +5 -2
- package/dist/decimal/index.js +63 -27
- package/dist/functools/index.d.ts +6 -30
- package/dist/functools/index.js +24 -56
- package/dist/globals/index.d.ts +3 -20
- package/dist/globals/index.js +23 -39
- package/dist/i18n/currency.d.ts +3 -0
- package/dist/i18n/currency.js +22 -7
- package/dist/i18n/date/index.d.ts +17 -10
- package/dist/i18n/date/index.js +79 -58
- package/dist/i18n/date/utils.d.ts +4 -5
- package/dist/i18n/date/utils.js +15 -113
- package/dist/i18n/duration.d.ts +11 -10
- package/dist/i18n/duration.js +38 -32
- package/dist/i18n/format.d.ts +5 -2
- package/dist/i18n/format.js +81 -209
- package/dist/i18n/index.d.ts +2 -1
- package/dist/itertools/index.d.ts +9 -13
- package/dist/itertools/index.js +38 -41
- package/dist/math/index.d.ts +10 -27
- package/dist/math/index.js +16 -33
- package/dist/operators/index.d.ts +1 -5
- package/dist/operators/index.js +60 -40
- 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/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,9 +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
|
|
5
|
+
export type { DateObject };
|
|
6
|
+
export type DateLike = number | string | Date | IntlDate | DateObject;
|
|
7
7
|
/**
|
|
8
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.
|
|
9
9
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl Intl Apis}
|
|
@@ -52,7 +52,7 @@ export declare class IntlDate {
|
|
|
52
52
|
dayOfYear(): number;
|
|
53
53
|
/** Returns `true` if this date's year is a leap year. */
|
|
54
54
|
isLeapYear(): boolean;
|
|
55
|
-
/** 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. */
|
|
56
56
|
weeksInYear(): number;
|
|
57
57
|
/** Gets the number of weeks in the current year, according to ISO weeks. */
|
|
58
58
|
isoWeeksInYear(): number;
|
|
@@ -128,13 +128,13 @@ export declare class IntlDate {
|
|
|
128
128
|
/** Returns the time part formatted as ISO8601.
|
|
129
129
|
* @example
|
|
130
130
|
```js
|
|
131
|
-
new IntlDate().toISOTime() // '
|
|
131
|
+
new IntlDate().toISOTime() // '22:44:30.652Z'
|
|
132
132
|
```
|
|
133
133
|
*/
|
|
134
134
|
toISOTime(): string;
|
|
135
135
|
/**
|
|
136
136
|
* Returns an object containing year, month, day-of-month, hours, minutes, seconds, milliseconds.
|
|
137
|
-
* @returns {Object} An object like `{year, month,
|
|
137
|
+
* @returns {Object} An object like `{year, month, day, hour, minute, second, millisecond}`
|
|
138
138
|
*/
|
|
139
139
|
toObject(): DateObject;
|
|
140
140
|
/** Returns the number of milliseconds since the Unix Epoch (January 1, 1970 UTC) */
|
|
@@ -185,19 +185,26 @@ export declare class IntlDate {
|
|
|
185
185
|
diff(other: DateLike, unit?: DurationUnit, exact?: boolean): number;
|
|
186
186
|
add(duration: TDuration, exact?: boolean): IntlDate;
|
|
187
187
|
subtract(duration: TDuration, exact?: boolean): IntlDate;
|
|
188
|
-
startOf(unit: DurationUnit):
|
|
189
|
-
endOf(unit: DurationUnit):
|
|
188
|
+
startOf(unit: DurationUnit): any;
|
|
189
|
+
endOf(unit: DurationUnit): any;
|
|
190
190
|
clone(date?: DateLike): IntlDate;
|
|
191
191
|
static max(...args: any[]): any;
|
|
192
192
|
static min(...args: any[]): any;
|
|
193
193
|
inspect(): string;
|
|
194
194
|
}
|
|
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
|
+
*/
|
|
195
202
|
export declare function addDuration(date: number | string | Date, duration: number | Duration | TDuration, exact?: boolean): Date;
|
|
196
203
|
/**
|
|
197
204
|
* Subtract the specified years, months, weeks, days, hours, minutes and seconds from the given date.
|
|
198
205
|
* @param date
|
|
199
206
|
* @param duration
|
|
200
|
-
* @param exact
|
|
207
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
201
208
|
* @returns
|
|
202
209
|
*/
|
|
203
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 };
|
|
@@ -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() {
|
|
@@ -321,9 +316,14 @@ export class IntlDate {
|
|
|
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,7 +332,7 @@ 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);
|
|
@@ -352,7 +352,22 @@ export class IntlDate {
|
|
|
352
352
|
}
|
|
353
353
|
diff(other, unit = 'milliseconds', exact = false) {
|
|
354
354
|
const dt = new IntlDate(other);
|
|
355
|
-
const
|
|
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);
|
|
@@ -392,16 +407,22 @@ export class IntlDate {
|
|
|
392
407
|
break;
|
|
393
408
|
case 'milliseconds':
|
|
394
409
|
break;
|
|
395
|
-
// no default,
|
|
410
|
+
// no default, an unknown unit changes nothing
|
|
396
411
|
}
|
|
397
412
|
if (normalizedUnit === 'weeks') {
|
|
398
|
-
|
|
413
|
+
return this.subtract({ days: this.dayOfWeek - 1 }).startOf('days');
|
|
399
414
|
}
|
|
400
415
|
if (normalizedUnit === 'quarters') {
|
|
401
416
|
const q = Math.ceil(this.month / 3);
|
|
402
417
|
obj.month = (q - 1) * 3 + 1;
|
|
403
418
|
}
|
|
404
|
-
|
|
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;
|
|
405
426
|
}
|
|
406
427
|
endOf(unit) {
|
|
407
428
|
return this.isValid()
|
|
@@ -420,57 +441,56 @@ export class IntlDate {
|
|
|
420
441
|
return minDate.apply(undefined, args);
|
|
421
442
|
}
|
|
422
443
|
inspect() {
|
|
423
|
-
return `new IntlDate("${this.toISOString()}")
|
|
444
|
+
return this.isValid() ? `new IntlDate("${this.toISOString()}")` : 'new IntlDate(NaN)';
|
|
424
445
|
}
|
|
425
446
|
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
return new Date(+endDate + postoffset);
|
|
434
|
-
}
|
|
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
|
+
*/
|
|
435
454
|
export function addDuration(date, duration, exact = false) {
|
|
436
|
-
|
|
437
|
-
const
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
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);
|
|
445
471
|
}
|
|
446
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;
|
|
447
476
|
switch (unit) {
|
|
448
|
-
case 'years':
|
|
449
|
-
date.setFullYear(date.getFullYear() + value);
|
|
450
|
-
break;
|
|
451
|
-
case 'quarters':
|
|
452
|
-
date.setMonth(date.getMonth() + value * 3);
|
|
453
|
-
break;
|
|
454
477
|
case 'months':
|
|
455
|
-
|
|
456
|
-
break;
|
|
457
|
-
case 'weeks':
|
|
458
|
-
date.setDate(date.getDate() + value * 7);
|
|
478
|
+
addMonths(date, value);
|
|
459
479
|
break;
|
|
460
480
|
case 'days':
|
|
461
481
|
date.setDate(date.getDate() + value);
|
|
462
482
|
break;
|
|
463
483
|
case 'hours':
|
|
464
|
-
date.
|
|
484
|
+
date.setTime(date.getTime() + value * 36e5);
|
|
465
485
|
break;
|
|
466
486
|
case 'minutes':
|
|
467
|
-
date.
|
|
487
|
+
date.setTime(date.getTime() + value * 6e4);
|
|
468
488
|
break;
|
|
469
489
|
case 'seconds':
|
|
470
|
-
date.
|
|
490
|
+
date.setTime(date.getTime() + value * 1e3);
|
|
471
491
|
break;
|
|
472
492
|
case 'milliseconds':
|
|
473
|
-
date.
|
|
493
|
+
date.setTime(date.getTime() + value);
|
|
474
494
|
break;
|
|
475
495
|
default:
|
|
476
496
|
break;
|
|
@@ -481,12 +501,13 @@ function setDateUnit(date, unit, value) {
|
|
|
481
501
|
* Subtract the specified years, months, weeks, days, hours, minutes and seconds from the given date.
|
|
482
502
|
* @param date
|
|
483
503
|
* @param duration
|
|
484
|
-
* @param exact
|
|
504
|
+
* @param exact Kept for callers that pass it, it no longer changes the result.
|
|
485
505
|
* @returns
|
|
486
506
|
*/
|
|
487
507
|
export function subDuration(date, duration, exact = false) {
|
|
488
508
|
return addDuration(date, new Duration(duration, exact).negated(), exact);
|
|
489
509
|
}
|
|
510
|
+
const MONTHS_IN_UNIT = { years: 12, quarters: 3, months: 1 };
|
|
490
511
|
const UNITS_SINGULAR = {
|
|
491
512
|
year: 'year',
|
|
492
513
|
years: 'year',
|
|
@@ -51,11 +51,10 @@ export declare function parseISODuration(s: any): any;
|
|
|
51
51
|
export declare function weeksInYear(year: number, firstDayOfWeek?: number, firstDayOfYear?: number): number;
|
|
52
52
|
/**
|
|
53
53
|
* Returns the week of the year for the specified date
|
|
54
|
-
* @param
|
|
55
|
-
* @param
|
|
56
|
-
* @param firstDayOfWeek
|
|
57
|
-
* @
|
|
58
|
-
* @returns
|
|
54
|
+
* @param date The date value
|
|
55
|
+
* @param firstDayOfWeek The weekday a week starts on, where Sunday is 0
|
|
56
|
+
* @param firstDayOfYear Picks week 1: the week holding January `7 + firstDayOfWeek - firstDayOfYear`, so `1, 4` gives ISO weeks
|
|
57
|
+
* @returns The week and the year that week belongs to
|
|
59
58
|
*/
|
|
60
59
|
export declare function weekOfYear(date: string | number | Date, firstDayOfWeek?: number, firstDayOfYear?: number): {
|
|
61
60
|
week: any;
|
package/dist/i18n/date/utils.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asDate } from '../format.js';
|
|
1
2
|
/**
|
|
2
3
|
* Returns x % n but takes the sign of n instead of x
|
|
3
4
|
* @param x
|
|
@@ -7,28 +8,13 @@
|
|
|
7
8
|
function floorMod(x, n) {
|
|
8
9
|
return x - n * Math.floor(x / n);
|
|
9
10
|
}
|
|
10
|
-
function padStart(input, n = 2) {
|
|
11
|
-
const isNeg = input < 0;
|
|
12
|
-
let padded;
|
|
13
|
-
if (isNeg) {
|
|
14
|
-
padded = '-' + ('' + -input).padStart(n, '0');
|
|
15
|
-
}
|
|
16
|
-
else {
|
|
17
|
-
padded = ('' + input).padStart(n, '0');
|
|
18
|
-
}
|
|
19
|
-
return padded;
|
|
20
|
-
}
|
|
21
|
-
function parseInteger(str) {
|
|
22
|
-
if (str != null && str !== '')
|
|
23
|
-
return parseInt(str, 10);
|
|
24
|
-
}
|
|
25
11
|
function parseFloating(str) {
|
|
26
12
|
if (str != null && str !== '')
|
|
27
13
|
return parseFloat(str);
|
|
28
14
|
}
|
|
29
15
|
function parseMilliseconds(str) {
|
|
30
16
|
if (str != null && str !== '') {
|
|
31
|
-
const f = parseFloat(
|
|
17
|
+
const f = parseFloat(`0.${str}`) * 1000;
|
|
32
18
|
return Math.floor(f);
|
|
33
19
|
}
|
|
34
20
|
}
|
|
@@ -39,7 +25,7 @@ export function minDate(...dates) {
|
|
|
39
25
|
ans = ans[0];
|
|
40
26
|
}
|
|
41
27
|
for (let i = 1; i < dates.length; i++) {
|
|
42
|
-
if (dates[i].valueOf() < ans.valueOf()) {
|
|
28
|
+
if (dates[i].valueOf() < ans.valueOf() || Number.isNaN(ans.valueOf())) {
|
|
43
29
|
ans = dates[i];
|
|
44
30
|
}
|
|
45
31
|
}
|
|
@@ -52,7 +38,7 @@ export function maxDate(...dates) {
|
|
|
52
38
|
ans = ans[0];
|
|
53
39
|
}
|
|
54
40
|
for (let i = 1; i < dates.length; i++) {
|
|
55
|
-
if (dates[i].valueOf() > ans.valueOf()) {
|
|
41
|
+
if (dates[i].valueOf() > ans.valueOf() || Number.isNaN(ans.valueOf())) {
|
|
56
42
|
ans = dates[i];
|
|
57
43
|
}
|
|
58
44
|
}
|
|
@@ -80,7 +66,7 @@ export function daysInYear(year) {
|
|
|
80
66
|
* @returns {number} Number of days in month
|
|
81
67
|
*/
|
|
82
68
|
export function daysInMonth(date) {
|
|
83
|
-
const d =
|
|
69
|
+
const d = asDate(date), year = d.getFullYear(), month = d.getMonth() + 1;
|
|
84
70
|
const modMonth = floorMod(month - 1, 12) + 1, modYear = year + (month - modMonth) / 12;
|
|
85
71
|
if (modMonth === 2) {
|
|
86
72
|
return isLeapYear(modYear) ? 29 : 28;
|
|
@@ -89,51 +75,6 @@ export function daysInMonth(date) {
|
|
|
89
75
|
return [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][modMonth - 1];
|
|
90
76
|
}
|
|
91
77
|
}
|
|
92
|
-
// covert a calendar object to a local timestamp (epoch, but with the offset baked in)
|
|
93
|
-
function objToLocalTS(obj) {
|
|
94
|
-
let d = Date.UTC(obj.year, obj.month - 1, obj.day, obj.hour, obj.minute, obj.second, obj.millisecond);
|
|
95
|
-
// for legacy reasons, years between 0 and 99 are interpreted as 19XX; revert that
|
|
96
|
-
if (obj.year < 100 && obj.year >= 0) {
|
|
97
|
-
let dt = new Date(d);
|
|
98
|
-
dt.setUTCFullYear(dt.getUTCFullYear() - 1900);
|
|
99
|
-
d = dt.getTime();
|
|
100
|
-
}
|
|
101
|
-
return +d;
|
|
102
|
-
}
|
|
103
|
-
function untruncateYear(year) {
|
|
104
|
-
if (year > 99) {
|
|
105
|
-
return year;
|
|
106
|
-
}
|
|
107
|
-
else
|
|
108
|
-
return year > 60 ? 1900 + year : 2000 + year;
|
|
109
|
-
}
|
|
110
|
-
// PARSING
|
|
111
|
-
function parseZoneInfo(ts, offsetFormat, locale, timeZone) {
|
|
112
|
-
const date = new Date(ts), intlOpts = {
|
|
113
|
-
hourCycle: 'h23',
|
|
114
|
-
year: 'numeric',
|
|
115
|
-
month: '2-digit',
|
|
116
|
-
day: '2-digit',
|
|
117
|
-
hour: '2-digit',
|
|
118
|
-
minute: '2-digit',
|
|
119
|
-
timeZone,
|
|
120
|
-
timeZoneName: offsetFormat
|
|
121
|
-
};
|
|
122
|
-
const parsed = new Intl.DateTimeFormat(locale, intlOpts)
|
|
123
|
-
.formatToParts(date)
|
|
124
|
-
.find((m) => m.type === 'timeZoneName');
|
|
125
|
-
return parsed?.value;
|
|
126
|
-
}
|
|
127
|
-
// signedOffset('-5', '30') -> -330
|
|
128
|
-
function signedOffset(offHourStr, offMinuteStr) {
|
|
129
|
-
let offHour = parseInt(offHourStr, 10);
|
|
130
|
-
// don't || this because we want to preserve -0
|
|
131
|
-
if (Number.isNaN(offHour)) {
|
|
132
|
-
offHour = 0;
|
|
133
|
-
}
|
|
134
|
-
const offMin = parseInt(offMinuteStr, 10) || 0, offMinSigned = offHour < 0 || Object.is(offHour, -0) ? -offMin : offMin;
|
|
135
|
-
return offHour * 60 + offMinSigned;
|
|
136
|
-
}
|
|
137
78
|
// COERCION
|
|
138
79
|
export function asNumber(value) {
|
|
139
80
|
const numericValue = Number(value);
|
|
@@ -141,24 +82,6 @@ export function asNumber(value) {
|
|
|
141
82
|
throw new Error(`Invalid unit value ${value}`);
|
|
142
83
|
return numericValue;
|
|
143
84
|
}
|
|
144
|
-
function formatOffset(offset, format) {
|
|
145
|
-
const hours = Math.trunc(Math.abs(offset / 60)), minutes = Math.trunc(Math.abs(offset % 60)), sign = offset >= 0 ? '+' : '-';
|
|
146
|
-
switch (format) {
|
|
147
|
-
case 'short':
|
|
148
|
-
return `${sign}${padStart(hours, 2)}:${padStart(minutes, 2)}`;
|
|
149
|
-
case 'narrow':
|
|
150
|
-
return `${sign}${hours}${minutes > 0 ? `:${minutes}` : ''}`;
|
|
151
|
-
case 'techie':
|
|
152
|
-
return `${sign}${padStart(hours, 2)}${padStart(minutes, 2)}`;
|
|
153
|
-
default:
|
|
154
|
-
throw new RangeError(`Value format ${format} is out of range for property format`);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
function timeObject(obj) {
|
|
158
|
-
const { hour, minute, second, millisecond } = obj;
|
|
159
|
-
return { hour, minute, second, millisecond };
|
|
160
|
-
}
|
|
161
|
-
const ianaRegex = /[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;
|
|
162
85
|
const isoDuration = /^-?P(?:(?:(-?\d{1,20}(?:\.\d{1,20})?)Y)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20}(?:\.\d{1,20})?)W)?(?:(-?\d{1,20}(?:\.\d{1,20})?)D)?(?:T(?:(-?\d{1,20}(?:\.\d{1,20})?)H)?(?:(-?\d{1,20}(?:\.\d{1,20})?)M)?(?:(-?\d{1,20})(?:[.,](-?\d{1,20}))?S)?)?)$/;
|
|
163
86
|
function extractISODuration(match) {
|
|
164
87
|
const [s, yearStr, monthStr, weekStr, dayStr, hourStr, minuteStr, secondStr, millisecondsStr] = match;
|
|
@@ -197,16 +120,15 @@ function createUTCDate(...args) {
|
|
|
197
120
|
let date, y = args[0];
|
|
198
121
|
// the Date.UTC function remaps years 0-99 to 1900-1999
|
|
199
122
|
if (y < 100 && y >= 0) {
|
|
200
|
-
args = Array.from(arguments);
|
|
201
123
|
// preserve leap years using a full 400 year cycle, then reset
|
|
202
124
|
args[0] = y + 400;
|
|
203
125
|
date = new Date(Date.UTC.apply(null, args));
|
|
204
|
-
if (isFinite(date.getUTCFullYear())) {
|
|
126
|
+
if (Number.isFinite(date.getUTCFullYear())) {
|
|
205
127
|
date.setUTCFullYear(y);
|
|
206
128
|
}
|
|
207
129
|
}
|
|
208
130
|
else {
|
|
209
|
-
date = new Date(Date.UTC.apply(null,
|
|
131
|
+
date = new Date(Date.UTC.apply(null, args));
|
|
210
132
|
}
|
|
211
133
|
return date;
|
|
212
134
|
}
|
|
@@ -217,26 +139,6 @@ function firstWeekOffset(year, dow, doy) {
|
|
|
217
139
|
fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;
|
|
218
140
|
return -fwdlw + fwd - 1;
|
|
219
141
|
}
|
|
220
|
-
// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday
|
|
221
|
-
function dayOfYearFromWeeks(year, week, weekday, dow, doy) {
|
|
222
|
-
var localWeekday = (7 + weekday - dow) % 7, weekOffset = firstWeekOffset(year, dow, doy), dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset, resYear, resDayOfYear;
|
|
223
|
-
if (dayOfYear <= 0) {
|
|
224
|
-
resYear = year - 1;
|
|
225
|
-
resDayOfYear = daysInYear(resYear) + dayOfYear;
|
|
226
|
-
}
|
|
227
|
-
else if (dayOfYear > daysInYear(year)) {
|
|
228
|
-
resYear = year + 1;
|
|
229
|
-
resDayOfYear = dayOfYear - daysInYear(year);
|
|
230
|
-
}
|
|
231
|
-
else {
|
|
232
|
-
resYear = year;
|
|
233
|
-
resDayOfYear = dayOfYear;
|
|
234
|
-
}
|
|
235
|
-
return {
|
|
236
|
-
year: resYear,
|
|
237
|
-
dayOfYear: resDayOfYear
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
142
|
/**
|
|
241
143
|
* Returns the number of weeks in the specified year.
|
|
242
144
|
* @param year
|
|
@@ -249,14 +151,13 @@ export function weeksInYear(year, firstDayOfWeek = 1, firstDayOfYear = 1) {
|
|
|
249
151
|
}
|
|
250
152
|
/**
|
|
251
153
|
* Returns the week of the year for the specified date
|
|
252
|
-
* @param
|
|
253
|
-
* @param
|
|
254
|
-
* @param firstDayOfWeek
|
|
255
|
-
* @
|
|
256
|
-
* @returns
|
|
154
|
+
* @param date The date value
|
|
155
|
+
* @param firstDayOfWeek The weekday a week starts on, where Sunday is 0
|
|
156
|
+
* @param firstDayOfYear Picks week 1: the week holding January `7 + firstDayOfWeek - firstDayOfYear`, so `1, 4` gives ISO weeks
|
|
157
|
+
* @returns The week and the year that week belongs to
|
|
257
158
|
*/
|
|
258
159
|
export function weekOfYear(date, firstDayOfWeek = 1, firstDayOfYear = 1) {
|
|
259
|
-
const year =
|
|
160
|
+
const year = asDate(date).getFullYear();
|
|
260
161
|
const doy = dayOfYear(date);
|
|
261
162
|
let weekOffset = firstWeekOffset(year, firstDayOfWeek, firstDayOfYear), week = Math.floor((doy - weekOffset - 1) / 7) + 1, resWeek, resYear;
|
|
262
163
|
if (week < 1) {
|
|
@@ -280,11 +181,12 @@ export function isoWeeksInYear(year) {
|
|
|
280
181
|
return weeksInYear(year, 1, 4);
|
|
281
182
|
}
|
|
282
183
|
export function dayOfYear(input) {
|
|
283
|
-
input =
|
|
184
|
+
input = asDate(input);
|
|
284
185
|
input.setHours(0);
|
|
285
186
|
input.setMinutes(0);
|
|
286
187
|
input.setSeconds(0);
|
|
287
188
|
input.setMilliseconds(0);
|
|
288
|
-
|
|
189
|
+
const start = new Date(input);
|
|
190
|
+
start.setMonth(0, 1);
|
|
289
191
|
return Math.round((+input - start.getTime()) / 864e5) + 1;
|
|
290
192
|
}
|