@naturalcycles/js-lib 14.232.0 → 14.233.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/datetime/dateInterval.d.ts +1 -2
- package/dist/datetime/dateInterval.js +5 -5
- package/dist/datetime/localDate.d.ts +125 -52
- package/dist/datetime/localDate.js +259 -201
- package/dist/datetime/localTime.d.ts +46 -51
- package/dist/datetime/localTime.js +181 -197
- package/dist/datetime/timeInterval.d.ts +1 -2
- package/dist/datetime/timeInterval.js +4 -4
- package/dist/env/buildInfo.js +1 -1
- package/dist-esm/datetime/dateInterval.js +6 -6
- package/dist-esm/datetime/localDate.js +259 -195
- package/dist-esm/datetime/localTime.js +177 -192
- package/dist-esm/datetime/timeInterval.js +5 -5
- package/dist-esm/env/buildInfo.js +2 -2
- package/package.json +2 -2
- package/src/datetime/dateInterval.ts +6 -7
- package/src/datetime/localDate.ts +307 -237
- package/src/datetime/localTime.ts +203 -212
- package/src/datetime/timeInterval.ts +6 -7
- package/src/env/buildInfo.ts +2 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.todayString = exports.
|
|
3
|
+
exports.todayString = exports.localDate = exports.LocalDate = void 0;
|
|
4
4
|
const assert_1 = require("../error/assert");
|
|
5
5
|
const iterable2_1 = require("../iter/iterable2");
|
|
6
6
|
const localTime_1 = require("./localTime");
|
|
7
7
|
const MDAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
8
8
|
const DATE_REGEX = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
9
9
|
/**
|
|
10
|
-
*
|
|
10
|
+
* LocalDate represents a date without time.
|
|
11
|
+
* It is timezone-independent.
|
|
11
12
|
*/
|
|
12
13
|
class LocalDate {
|
|
13
14
|
constructor($year, $month, $day) {
|
|
@@ -15,90 +16,6 @@ class LocalDate {
|
|
|
15
16
|
this.$month = $month;
|
|
16
17
|
this.$day = $day;
|
|
17
18
|
}
|
|
18
|
-
static create(year, month, day) {
|
|
19
|
-
return new LocalDate(year, month, day);
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Parses input into LocalDate.
|
|
23
|
-
* Input can already be a LocalDate - it is returned as-is in that case.
|
|
24
|
-
*/
|
|
25
|
-
static of(d) {
|
|
26
|
-
const t = this.parseOrNull(d);
|
|
27
|
-
(0, assert_1._assert)(t !== null, `Cannot parse "${d}" into LocalDate`, {
|
|
28
|
-
input: d,
|
|
29
|
-
});
|
|
30
|
-
return t;
|
|
31
|
-
}
|
|
32
|
-
static parseCompact(d) {
|
|
33
|
-
const [year, month, day] = [d.slice(0, 4), d.slice(4, 2), d.slice(6, 2)].map(Number);
|
|
34
|
-
(0, assert_1._assert)(day && month && year, `Cannot parse "${d}" into LocalDate`);
|
|
35
|
-
return new LocalDate(year, month, day);
|
|
36
|
-
}
|
|
37
|
-
static fromDate(d) {
|
|
38
|
-
return new LocalDate(d.getFullYear(), d.getMonth() + 1, d.getDate());
|
|
39
|
-
}
|
|
40
|
-
static fromDateUTC(d) {
|
|
41
|
-
return new LocalDate(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Returns null if invalid.
|
|
45
|
-
*/
|
|
46
|
-
static parseOrNull(d) {
|
|
47
|
-
if (!d)
|
|
48
|
-
return null;
|
|
49
|
-
if (d instanceof LocalDate)
|
|
50
|
-
return d;
|
|
51
|
-
if (d instanceof Date) {
|
|
52
|
-
return this.fromDate(d);
|
|
53
|
-
}
|
|
54
|
-
const matches = typeof d === 'string' && DATE_REGEX.exec(d.slice(0, 10));
|
|
55
|
-
if (!matches)
|
|
56
|
-
return null;
|
|
57
|
-
const year = Number(matches[1]);
|
|
58
|
-
const month = Number(matches[2]);
|
|
59
|
-
const day = Number(matches[3]);
|
|
60
|
-
if (!year ||
|
|
61
|
-
!month ||
|
|
62
|
-
month < 1 ||
|
|
63
|
-
month > 12 ||
|
|
64
|
-
!day ||
|
|
65
|
-
day < 1 ||
|
|
66
|
-
day > this.getMonthLength(year, month)) {
|
|
67
|
-
return null;
|
|
68
|
-
}
|
|
69
|
-
return new LocalDate(year, month, day);
|
|
70
|
-
}
|
|
71
|
-
static isValid(iso) {
|
|
72
|
-
return this.parseOrNull(iso) !== null;
|
|
73
|
-
}
|
|
74
|
-
static today() {
|
|
75
|
-
return this.fromDate(new Date());
|
|
76
|
-
}
|
|
77
|
-
static todayUTC() {
|
|
78
|
-
return this.fromDateUTC(new Date());
|
|
79
|
-
}
|
|
80
|
-
static sort(items, mutate = false, dir = 'asc') {
|
|
81
|
-
const mod = dir === 'desc' ? -1 : 1;
|
|
82
|
-
return (mutate ? items : [...items]).sort((a, b) => a.cmp(b) * mod);
|
|
83
|
-
}
|
|
84
|
-
static earliestOrUndefined(items) {
|
|
85
|
-
return items.length ? LocalDate.earliest(items) : undefined;
|
|
86
|
-
}
|
|
87
|
-
static earliest(items) {
|
|
88
|
-
(0, assert_1._assert)(items.length, 'LocalDate.earliest called on empty array');
|
|
89
|
-
return items
|
|
90
|
-
.map(i => LocalDate.of(i))
|
|
91
|
-
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
92
|
-
}
|
|
93
|
-
static latestOrUndefined(items) {
|
|
94
|
-
return items.length ? LocalDate.latest(items) : undefined;
|
|
95
|
-
}
|
|
96
|
-
static latest(items) {
|
|
97
|
-
(0, assert_1._assert)(items.length, 'LocalDate.latest called on empty array');
|
|
98
|
-
return items
|
|
99
|
-
.map(i => LocalDate.of(i))
|
|
100
|
-
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
101
|
-
}
|
|
102
19
|
get(unit) {
|
|
103
20
|
return unit === 'year' ? this.$year : unit === 'month' ? this.$month : this.$day;
|
|
104
21
|
}
|
|
@@ -128,7 +45,7 @@ class LocalDate {
|
|
|
128
45
|
return (this.toDate().getDay() || 7);
|
|
129
46
|
}
|
|
130
47
|
isSame(d) {
|
|
131
|
-
d =
|
|
48
|
+
d = exports.localDate.of(d);
|
|
132
49
|
return this.$day === d.$day && this.$month === d.$month && this.$year === d.$year;
|
|
133
50
|
}
|
|
134
51
|
isBefore(d, inclusive = false) {
|
|
@@ -165,13 +82,13 @@ class LocalDate {
|
|
|
165
82
|
* Third argument allows to override "today".
|
|
166
83
|
*/
|
|
167
84
|
isOlderThan(n, unit, today) {
|
|
168
|
-
return this.isBefore(
|
|
85
|
+
return this.isBefore(exports.localDate.of(today || new Date()).plus(-n, unit));
|
|
169
86
|
}
|
|
170
87
|
/**
|
|
171
88
|
* Checks if this localDate is same or older (<=) than "today" by X units.
|
|
172
89
|
*/
|
|
173
90
|
isSameOrOlderThan(n, unit, today) {
|
|
174
|
-
return this.isSameOrBefore(
|
|
91
|
+
return this.isSameOrBefore(exports.localDate.of(today || new Date()).plus(-n, unit));
|
|
175
92
|
}
|
|
176
93
|
/**
|
|
177
94
|
* Checks if this localDate is younger (>) than "today" by X units.
|
|
@@ -183,13 +100,13 @@ class LocalDate {
|
|
|
183
100
|
* Third argument allows to override "today".
|
|
184
101
|
*/
|
|
185
102
|
isYoungerThan(n, unit, today) {
|
|
186
|
-
return this.isAfter(
|
|
103
|
+
return this.isAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
|
|
187
104
|
}
|
|
188
105
|
/**
|
|
189
106
|
* Checks if this localDate is same or younger (>=) than "today" by X units.
|
|
190
107
|
*/
|
|
191
108
|
isSameOrYoungerThan(n, unit, today) {
|
|
192
|
-
return this.isSameOrAfter(
|
|
109
|
+
return this.isSameOrAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
|
|
193
110
|
}
|
|
194
111
|
/**
|
|
195
112
|
* Returns 1 if this > d
|
|
@@ -197,7 +114,7 @@ class LocalDate {
|
|
|
197
114
|
* returns -1 if this < d
|
|
198
115
|
*/
|
|
199
116
|
cmp(d) {
|
|
200
|
-
d =
|
|
117
|
+
d = exports.localDate.of(d);
|
|
201
118
|
if (this.$year < d.$year)
|
|
202
119
|
return -1;
|
|
203
120
|
if (this.$year > d.$year)
|
|
@@ -224,7 +141,7 @@ class LocalDate {
|
|
|
224
141
|
* a.diff(b) means "a minus b"
|
|
225
142
|
*/
|
|
226
143
|
diff(d, unit) {
|
|
227
|
-
d =
|
|
144
|
+
d = exports.localDate.of(d);
|
|
228
145
|
const sign = this.cmp(d);
|
|
229
146
|
if (!sign)
|
|
230
147
|
return 0;
|
|
@@ -235,8 +152,8 @@ class LocalDate {
|
|
|
235
152
|
if (big.$month < small.$month ||
|
|
236
153
|
(big.$month === small.$month &&
|
|
237
154
|
big.$day < small.$day &&
|
|
238
|
-
!(big.$day ===
|
|
239
|
-
small.$day ===
|
|
155
|
+
!(big.$day === exports.localDate.getMonthLength(big.$year, big.$month) &&
|
|
156
|
+
small.$day === exports.localDate.getMonthLength(small.$year, small.$month)))) {
|
|
240
157
|
years--;
|
|
241
158
|
}
|
|
242
159
|
return years * sign || 0;
|
|
@@ -244,7 +161,7 @@ class LocalDate {
|
|
|
244
161
|
if (unit === 'month') {
|
|
245
162
|
let months = (big.$year - small.$year) * 12 + (big.$month - small.$month);
|
|
246
163
|
if (big.$day < small.$day) {
|
|
247
|
-
const bigMonthLen =
|
|
164
|
+
const bigMonthLen = exports.localDate.getMonthLength(big.$year, big.$month);
|
|
248
165
|
if (big.$day !== bigMonthLen || small.$day < bigMonthLen) {
|
|
249
166
|
months--;
|
|
250
167
|
}
|
|
@@ -256,16 +173,16 @@ class LocalDate {
|
|
|
256
173
|
// If small date is after 1st of March - next year's "leapness" should be used
|
|
257
174
|
const offsetYear = small.$month >= 3 ? 1 : 0;
|
|
258
175
|
for (let year = small.$year; year < big.$year; year++) {
|
|
259
|
-
days +=
|
|
176
|
+
days += exports.localDate.getYearLength(year + offsetYear);
|
|
260
177
|
}
|
|
261
178
|
if (small.$month < big.$month) {
|
|
262
179
|
for (let month = small.$month; month < big.$month; month++) {
|
|
263
|
-
days +=
|
|
180
|
+
days += exports.localDate.getMonthLength(big.$year, month);
|
|
264
181
|
}
|
|
265
182
|
}
|
|
266
183
|
else if (big.$month < small.$month) {
|
|
267
184
|
for (let month = big.$month; month < small.$month; month++) {
|
|
268
|
-
days -=
|
|
185
|
+
days -= exports.localDate.getMonthLength(big.$year, month);
|
|
269
186
|
}
|
|
270
187
|
}
|
|
271
188
|
if (unit === 'week') {
|
|
@@ -306,11 +223,11 @@ class LocalDate {
|
|
|
306
223
|
$year -= 1;
|
|
307
224
|
$month += 12;
|
|
308
225
|
}
|
|
309
|
-
$day +=
|
|
226
|
+
$day += exports.localDate.getMonthLength($year, $month);
|
|
310
227
|
}
|
|
311
228
|
}
|
|
312
229
|
else {
|
|
313
|
-
let monLen =
|
|
230
|
+
let monLen = exports.localDate.getMonthLength($year, $month);
|
|
314
231
|
if (unit !== 'day') {
|
|
315
232
|
if ($day > monLen) {
|
|
316
233
|
// Case of 2022-05-31 plus 1 month should be 2022-06-30, not 31
|
|
@@ -325,7 +242,7 @@ class LocalDate {
|
|
|
325
242
|
$year += 1;
|
|
326
243
|
$month -= 12;
|
|
327
244
|
}
|
|
328
|
-
monLen =
|
|
245
|
+
monLen = exports.localDate.getMonthLength($year, $month);
|
|
329
246
|
}
|
|
330
247
|
}
|
|
331
248
|
}
|
|
@@ -344,35 +261,24 @@ class LocalDate {
|
|
|
344
261
|
if (unit === 'day')
|
|
345
262
|
return this;
|
|
346
263
|
if (unit === 'month')
|
|
347
|
-
return LocalDate
|
|
264
|
+
return new LocalDate(this.$year, this.$month, 1);
|
|
348
265
|
// year
|
|
349
|
-
return LocalDate
|
|
266
|
+
return new LocalDate(this.$year, 1, 1);
|
|
350
267
|
}
|
|
351
268
|
endOf(unit) {
|
|
352
269
|
if (unit === 'day')
|
|
353
270
|
return this;
|
|
354
271
|
if (unit === 'month')
|
|
355
|
-
return LocalDate
|
|
272
|
+
return new LocalDate(this.$year, this.$month, exports.localDate.getMonthLength(this.$year, this.$month));
|
|
356
273
|
// year
|
|
357
|
-
return LocalDate
|
|
274
|
+
return new LocalDate(this.$year, 12, 31);
|
|
358
275
|
}
|
|
359
276
|
/**
|
|
360
277
|
* Returns how many days are in the current month.
|
|
361
278
|
* E.g 31 for January.
|
|
362
279
|
*/
|
|
363
280
|
daysInMonth() {
|
|
364
|
-
return
|
|
365
|
-
}
|
|
366
|
-
static getYearLength(year) {
|
|
367
|
-
return this.isLeapYear(year) ? 366 : 365;
|
|
368
|
-
}
|
|
369
|
-
static getMonthLength(year, month) {
|
|
370
|
-
if (month === 2)
|
|
371
|
-
return this.isLeapYear(year) ? 29 : 28;
|
|
372
|
-
return MDAYS[month];
|
|
373
|
-
}
|
|
374
|
-
static isLeapYear(year) {
|
|
375
|
-
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
281
|
+
return exports.localDate.getMonthLength(this.$year, this.$month);
|
|
376
282
|
}
|
|
377
283
|
clone() {
|
|
378
284
|
return new LocalDate(this.$year, this.$month, this.$day);
|
|
@@ -391,33 +297,45 @@ class LocalDate {
|
|
|
391
297
|
* Unlike normal `.toDate` that uses browser's timezone by default.
|
|
392
298
|
*/
|
|
393
299
|
toDateInUTC() {
|
|
394
|
-
return new Date(this.
|
|
300
|
+
return new Date(this.toISODateTimeInUTC());
|
|
395
301
|
}
|
|
302
|
+
/**
|
|
303
|
+
* Converts LocalDate to LocalTime with 0 hours, 0 minutes, 0 seconds.
|
|
304
|
+
* LocalTime's Date will be in local timezone.
|
|
305
|
+
*/
|
|
396
306
|
toLocalTime() {
|
|
397
|
-
return localTime_1.
|
|
307
|
+
return localTime_1.localTime.of(this.toDate());
|
|
398
308
|
}
|
|
309
|
+
/**
|
|
310
|
+
* Returns e.g: `1984-06-21`
|
|
311
|
+
*/
|
|
399
312
|
toISODate() {
|
|
400
|
-
return
|
|
313
|
+
return [
|
|
314
|
+
String(this.$year).padStart(4, '0'),
|
|
315
|
+
String(this.$month).padStart(2, '0'),
|
|
316
|
+
String(this.$day).padStart(2, '0'),
|
|
317
|
+
].join('-');
|
|
401
318
|
}
|
|
402
319
|
/**
|
|
403
|
-
* Returns e.g: `1984-06-
|
|
320
|
+
* Returns e.g: `1984-06-21T00:00:00`
|
|
321
|
+
* Hours, minutes and seconds are 0.
|
|
404
322
|
*/
|
|
405
323
|
toISODateTime() {
|
|
406
|
-
return this.
|
|
324
|
+
return this.toISODate() + 'T00:00:00';
|
|
407
325
|
}
|
|
408
326
|
/**
|
|
409
|
-
* Returns e.g: `1984-06-
|
|
327
|
+
* Returns e.g: `1984-06-21T00:00:00Z` (notice the Z at the end, which indicates UTC).
|
|
328
|
+
* Hours, minutes and seconds are 0.
|
|
410
329
|
*/
|
|
411
|
-
|
|
330
|
+
toISODateTimeInUTC() {
|
|
412
331
|
return this.toISODateTime() + 'Z';
|
|
413
332
|
}
|
|
414
333
|
toString() {
|
|
415
|
-
return
|
|
416
|
-
String(this.$year).padStart(4, '0'),
|
|
417
|
-
String(this.$month).padStart(2, '0'),
|
|
418
|
-
String(this.$day).padStart(2, '0'),
|
|
419
|
-
].join('-');
|
|
334
|
+
return this.toISODate();
|
|
420
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Returns e.g: `19840621`
|
|
338
|
+
*/
|
|
421
339
|
toStringCompact() {
|
|
422
340
|
return [
|
|
423
341
|
String(this.$year).padStart(4, '0'),
|
|
@@ -425,18 +343,26 @@ class LocalDate {
|
|
|
425
343
|
String(this.$day).padStart(2, '0'),
|
|
426
344
|
].join('');
|
|
427
345
|
}
|
|
346
|
+
/**
|
|
347
|
+
* Returns e.g: `1984-06`
|
|
348
|
+
*/
|
|
428
349
|
toMonthId() {
|
|
429
|
-
return this.
|
|
350
|
+
return this.toISODate().slice(0, 7);
|
|
430
351
|
}
|
|
431
|
-
|
|
352
|
+
/**
|
|
353
|
+
* Returns unix timestamp of 00:00:00 of that date (in UTC, because unix timestamp always reflects UTC).
|
|
354
|
+
*/
|
|
432
355
|
unix() {
|
|
433
356
|
return Math.floor(this.toDate().valueOf() / 1000);
|
|
434
357
|
}
|
|
358
|
+
/**
|
|
359
|
+
* Same as .unix(), but in milliseconds.
|
|
360
|
+
*/
|
|
435
361
|
unixMillis() {
|
|
436
362
|
return this.toDate().valueOf();
|
|
437
363
|
}
|
|
438
364
|
toJSON() {
|
|
439
|
-
return this.
|
|
365
|
+
return this.toISODate();
|
|
440
366
|
}
|
|
441
367
|
format(fmt) {
|
|
442
368
|
if (fmt instanceof Intl.DateTimeFormat) {
|
|
@@ -446,78 +372,210 @@ class LocalDate {
|
|
|
446
372
|
}
|
|
447
373
|
}
|
|
448
374
|
exports.LocalDate = LocalDate;
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
375
|
+
class LocalDateFactory {
|
|
376
|
+
/**
|
|
377
|
+
* Create LocalDate from year, month and day components.
|
|
378
|
+
*/
|
|
379
|
+
create(year, month, day) {
|
|
380
|
+
return new LocalDate(year, month, day);
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* Create LocalDate from LocalDateInput.
|
|
384
|
+
* Input can already be a LocalDate - it is returned as-is in that case.
|
|
385
|
+
* String - will be parsed as yyyy-mm-dd.
|
|
386
|
+
* Date - will be converted to LocalDate (as-is, in whatever timezone it is - local or UTC).
|
|
387
|
+
* No other formats are supported.
|
|
388
|
+
*
|
|
389
|
+
* Will throw if it fails to parse/construct LocalDate.
|
|
390
|
+
*/
|
|
391
|
+
of(d) {
|
|
392
|
+
const t = this.parseOrNull(d);
|
|
393
|
+
(0, assert_1._assert)(t !== null, `Cannot parse "${d}" into LocalDate`, {
|
|
394
|
+
input: d,
|
|
395
|
+
});
|
|
396
|
+
return t;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Tries to construct LocalDate from LocalDateInput, returns null otherwise.
|
|
400
|
+
* Does not throw (returns null instead).
|
|
401
|
+
*/
|
|
402
|
+
parseOrNull(d) {
|
|
403
|
+
if (!d)
|
|
404
|
+
return null;
|
|
405
|
+
if (d instanceof LocalDate)
|
|
406
|
+
return d;
|
|
407
|
+
if (d instanceof Date) {
|
|
408
|
+
return this.fromDate(d);
|
|
409
|
+
}
|
|
410
|
+
const matches = typeof d === 'string' && DATE_REGEX.exec(d.slice(0, 10));
|
|
411
|
+
if (!matches)
|
|
412
|
+
return null;
|
|
413
|
+
const year = Number(matches[1]);
|
|
414
|
+
const month = Number(matches[2]);
|
|
415
|
+
const day = Number(matches[3]);
|
|
416
|
+
if (!year ||
|
|
417
|
+
!month ||
|
|
418
|
+
month < 1 ||
|
|
419
|
+
month > 12 ||
|
|
420
|
+
!day ||
|
|
421
|
+
day < 1 ||
|
|
422
|
+
day > this.getMonthLength(year, month)) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
return new LocalDate(year, month, day);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Parses "compact iso8601 format", e.g `19840621` into LocalDate.
|
|
429
|
+
* Throws if it fails to do so.
|
|
430
|
+
*/
|
|
431
|
+
parseCompact(d) {
|
|
432
|
+
const [year, month, day] = [d.slice(0, 4), d.slice(4, 2), d.slice(6, 2)].map(Number);
|
|
433
|
+
(0, assert_1._assert)(day && month && year, `Cannot parse "${d}" into LocalDate`);
|
|
434
|
+
return new LocalDate(year, month, day);
|
|
435
|
+
}
|
|
436
|
+
getYearLength(year) {
|
|
437
|
+
return this.isLeapYear(year) ? 366 : 365;
|
|
438
|
+
}
|
|
439
|
+
getMonthLength(year, month) {
|
|
440
|
+
if (month === 2)
|
|
441
|
+
return this.isLeapYear(year) ? 29 : 28;
|
|
442
|
+
return MDAYS[month];
|
|
443
|
+
}
|
|
444
|
+
isLeapYear(year) {
|
|
445
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Constructs LocalDate from Date.
|
|
449
|
+
* Takes Date as-is, in its timezone - local or UTC.
|
|
450
|
+
*/
|
|
451
|
+
fromDate(d) {
|
|
452
|
+
return new LocalDate(d.getFullYear(), d.getMonth() + 1, d.getDate());
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Constructs LocalDate from Date.
|
|
456
|
+
* Takes Date's year/month/day components in UTC, using getUTCFullYear, getUTCMonth, getUTCDate.
|
|
457
|
+
*/
|
|
458
|
+
fromDateInUTC(d) {
|
|
459
|
+
return new LocalDate(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Returns true if isoString is a valid iso8601 string like `yyyy-mm-dd`.
|
|
463
|
+
*/
|
|
464
|
+
isValid(isoString) {
|
|
465
|
+
return this.parseOrNull(isoString) !== null;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Creates LocalDate that represents `today` (in local timezone).
|
|
469
|
+
*/
|
|
470
|
+
today() {
|
|
471
|
+
return this.fromDate(new Date());
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Creates LocalDate that represents `today` in UTC.
|
|
475
|
+
*/
|
|
476
|
+
todayInUTC() {
|
|
477
|
+
return this.fromDateInUTC(new Date());
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Sorts an array of LocalDates in `dir` order (ascending by default).
|
|
481
|
+
*/
|
|
482
|
+
sort(items, dir = 'asc', mutate = false) {
|
|
483
|
+
const mod = dir === 'desc' ? -1 : 1;
|
|
484
|
+
return (mutate ? items : [...items]).sort((a, b) => a.cmp(b) * mod);
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Returns the earliest (min) LocalDate from the array, or undefined if the array is empty.
|
|
488
|
+
*/
|
|
489
|
+
minOrUndefined(items) {
|
|
490
|
+
return items.length ? this.min(items) : undefined;
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Returns the earliest LocalDate from the array.
|
|
494
|
+
* Throws if the array is empty.
|
|
495
|
+
*/
|
|
496
|
+
min(items) {
|
|
497
|
+
(0, assert_1._assert)(items.length, 'localDate.min called on empty array');
|
|
498
|
+
return items.map(i => this.of(i)).reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
499
|
+
}
|
|
500
|
+
/**
|
|
501
|
+
* Returns the latest (max) LocalDate from the array, or undefined if the array is empty.
|
|
502
|
+
*/
|
|
503
|
+
maxOrUndefined(items) {
|
|
504
|
+
return items.length ? this.max(items) : undefined;
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Returns the latest LocalDate from the array.
|
|
508
|
+
* Throws if the array is empty.
|
|
509
|
+
*/
|
|
510
|
+
max(items) {
|
|
511
|
+
(0, assert_1._assert)(items.length, 'localDate.max called on empty array');
|
|
512
|
+
return items.map(i => this.of(i)).reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Returns the range (array) of LocalDates between min and max.
|
|
516
|
+
* By default, min is included, max is excluded.
|
|
517
|
+
*/
|
|
518
|
+
range(min, max, incl = '[)', step = 1, stepUnit = 'day') {
|
|
519
|
+
return this.rangeIterable(min, max, incl, step, stepUnit).toArray();
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Returns the Iterable2 of LocalDates between min and max.
|
|
523
|
+
* By default, min is included, max is excluded.
|
|
524
|
+
*/
|
|
525
|
+
rangeIterable(min, max, incl = '[)', step = 1, stepUnit = 'day') {
|
|
526
|
+
if (stepUnit === 'week') {
|
|
527
|
+
step *= 7;
|
|
528
|
+
stepUnit = 'day';
|
|
529
|
+
}
|
|
530
|
+
const $min = this.of(min).startOf(stepUnit);
|
|
531
|
+
const $max = this.of(max).startOf(stepUnit);
|
|
532
|
+
let value = $min;
|
|
533
|
+
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
534
|
+
if (value.isAfter($min, incl[0] === '[')) {
|
|
535
|
+
// ok
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
value.plus(1, stepUnit, true);
|
|
539
|
+
}
|
|
540
|
+
const rightInclusive = incl[1] === ']';
|
|
541
|
+
return iterable2_1.Iterable2.of({
|
|
542
|
+
*[Symbol.iterator]() {
|
|
543
|
+
while (value.isBefore($max, rightInclusive)) {
|
|
544
|
+
yield value;
|
|
545
|
+
// We don't mutate, because we already returned `current`
|
|
546
|
+
// in the previous iteration
|
|
547
|
+
value = value.plus(step, stepUnit);
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Creates a LocalDate from the input, unless it's falsy - then returns undefined.
|
|
554
|
+
*
|
|
555
|
+
* Similar to `localDate.orToday`, but that will instead return Today on falsy input.
|
|
556
|
+
*/
|
|
557
|
+
orUndefined(d) {
|
|
558
|
+
return d ? this.of(d) : undefined;
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* Creates a LocalDate from the input, unless it's falsy - then returns localDate.today.
|
|
562
|
+
*/
|
|
563
|
+
orToday(d) {
|
|
564
|
+
return d ? this.of(d) : this.today();
|
|
565
|
+
}
|
|
512
566
|
}
|
|
513
|
-
|
|
567
|
+
const localDateFactory = new LocalDateFactory();
|
|
568
|
+
// export const localDate = Object.assign((d: LocalDateInput) => {
|
|
569
|
+
// return localDateFactory.of(d)
|
|
570
|
+
// }, localDateFactory) as LocalDateFn
|
|
571
|
+
exports.localDate = localDateFactory.of.bind(localDateFactory);
|
|
572
|
+
// The line below is the blackest of black magic I have ever written in 2024.
|
|
573
|
+
// And probably 2023 as well.
|
|
574
|
+
Object.setPrototypeOf(exports.localDate, localDateFactory);
|
|
514
575
|
/**
|
|
515
576
|
Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
|
|
516
577
|
*/
|
|
517
578
|
function todayString() {
|
|
518
|
-
|
|
519
|
-
// return new Date().toISOString().slice(0, 10)
|
|
520
|
-
// But, toISOString always returns the date in UTC, so in the Browser it would give unexpected result!
|
|
521
|
-
return LocalDate.fromDate(new Date()).toString();
|
|
579
|
+
return exports.localDate.fromDate(new Date()).toISODate();
|
|
522
580
|
}
|
|
523
581
|
exports.todayString = todayString;
|