@naturalcycles/js-lib 14.243.1 → 14.245.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 -1
- package/dist/datetime/dateInterval.js +1 -1
- package/dist/datetime/localDate.d.ts +75 -51
- package/dist/datetime/localDate.js +256 -200
- package/dist/datetime/localTime.d.ts +88 -56
- package/dist/datetime/localTime.js +277 -176
- package/dist/datetime/timeInterval.d.ts +2 -2
- package/dist/datetime/timeInterval.js +2 -2
- package/dist/env/buildInfo.js +2 -2
- package/dist/error/error.util.d.ts +1 -1
- package/dist/index.d.ts +37 -37
- package/dist/index.js +37 -37
- package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +1 -1
- package/dist/json-schema/jsonSchemaBuilder.d.ts +1 -1
- package/dist/object/object.util.d.ts +1 -1
- package/dist/time/time.util.js +4 -2
- package/dist/zod/zod.util.d.ts +1 -1
- package/dist-esm/datetime/dateInterval.js +1 -1
- package/dist-esm/datetime/localDate.js +256 -199
- package/dist-esm/datetime/localTime.js +277 -175
- package/dist-esm/datetime/timeInterval.js +2 -2
- package/dist-esm/decorators/logMethod.decorator.js +1 -1
- package/dist-esm/env/buildInfo.js +2 -2
- package/dist-esm/index.js +37 -37
- package/dist-esm/json-schema/jsonSchemaBuilder.js +1 -1
- package/dist-esm/time/time.util.js +4 -2
- package/package.json +1 -1
- package/src/datetime/dateInterval.ts +2 -2
- package/src/datetime/localDate.ts +259 -215
- package/src/datetime/localTime.ts +277 -209
- package/src/datetime/timeInterval.ts +4 -4
- package/src/decorators/logMethod.decorator.ts +1 -1
- package/src/define.ts +1 -1
- package/src/env/buildInfo.ts +2 -2
- package/src/error/error.util.ts +3 -3
- package/src/http/fetcher.ts +1 -1
- package/src/index.ts +37 -37
- package/src/json-schema/from-data/generateJsonSchemaFromData.ts +1 -1
- package/src/json-schema/jsonSchemaBuilder.ts +2 -2
- package/src/object/object.util.ts +1 -1
- package/src/time/time.util.ts +4 -1
- package/src/zod/zod.util.ts +1 -1
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.localTime = exports.LocalTime = exports.ISODayOfWeek = void 0;
|
|
4
|
-
exports.nowUnix = nowUnix;
|
|
5
4
|
const assert_1 = require("../error/assert");
|
|
6
5
|
const is_util_1 = require("../is.util");
|
|
7
6
|
const time_util_1 = require("../time/time.util");
|
|
@@ -23,10 +22,22 @@ const SECONDS_IN_DAY = 86400;
|
|
|
23
22
|
// const MILLISECONDS_IN_DAY = 86400000
|
|
24
23
|
// const MILLISECONDS_IN_MINUTE = 60000
|
|
25
24
|
const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
/**
|
|
26
|
+
* It supports 2 forms:
|
|
27
|
+
* 1. 2023-03-03
|
|
28
|
+
* 2. 2023-03-03T05:10:02
|
|
29
|
+
* // todo: make it even looser, like Day.js
|
|
30
|
+
*/
|
|
31
|
+
const DATE_TIME_REGEX_LOOSE = /^(\d{4})-(\d{2})-(\d{2})([Tt\s](\d{2}):?(\d{2})?:?(\d{2})?)?/;
|
|
32
|
+
/**
|
|
33
|
+
* Supports 2 forms:
|
|
34
|
+
* 1. 2023-03-03
|
|
35
|
+
* 2. 2023-03-03T05:10:02
|
|
36
|
+
* Ok, now it allows arbitrary stuff after `:ss`, to allow millis/timezone info,
|
|
37
|
+
* but it will not take it into account.
|
|
38
|
+
*/
|
|
39
|
+
const DATE_TIME_REGEX_STRICT = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})/;
|
|
40
|
+
const DATE_REGEX_STRICT = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
30
41
|
class LocalTime {
|
|
31
42
|
constructor($date) {
|
|
32
43
|
this.$date = $date;
|
|
@@ -35,14 +46,14 @@ class LocalTime {
|
|
|
35
46
|
* Returns [cloned] LocalTime that is based on the same unixtimestamp, but in UTC timezone.
|
|
36
47
|
* Opposite of `.local()` method.
|
|
37
48
|
*/
|
|
38
|
-
|
|
49
|
+
toUTC() {
|
|
39
50
|
return new LocalTime(new Date(this.$date.toISOString()));
|
|
40
51
|
}
|
|
41
52
|
/**
|
|
42
53
|
* Returns [cloned] LocalTime that is based on the same unixtimestamp, but in local timezone.
|
|
43
54
|
* Opposite of `.utc()` method.
|
|
44
55
|
*/
|
|
45
|
-
|
|
56
|
+
toLocal() {
|
|
46
57
|
return new LocalTime(new Date(this.$date.getTime()));
|
|
47
58
|
}
|
|
48
59
|
/**
|
|
@@ -164,34 +175,58 @@ class LocalTime {
|
|
|
164
175
|
}
|
|
165
176
|
return t;
|
|
166
177
|
}
|
|
167
|
-
year(
|
|
168
|
-
return
|
|
178
|
+
get year() {
|
|
179
|
+
return this.$date.getFullYear();
|
|
169
180
|
}
|
|
170
|
-
|
|
171
|
-
return
|
|
181
|
+
setYear(v) {
|
|
182
|
+
return this.set('year', v);
|
|
172
183
|
}
|
|
173
|
-
|
|
174
|
-
return
|
|
184
|
+
get month() {
|
|
185
|
+
return this.$date.getMonth() + 1;
|
|
175
186
|
}
|
|
176
|
-
|
|
177
|
-
return
|
|
187
|
+
setMonth(v) {
|
|
188
|
+
return this.set('month', v);
|
|
178
189
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
get week() {
|
|
191
|
+
return getWeek(this.$date);
|
|
192
|
+
}
|
|
193
|
+
setWeek(v) {
|
|
194
|
+
return this.set('week', v);
|
|
195
|
+
}
|
|
196
|
+
get day() {
|
|
197
|
+
return this.$date.getDate();
|
|
198
|
+
}
|
|
199
|
+
setDay(v) {
|
|
200
|
+
return this.set('day', v);
|
|
201
|
+
}
|
|
202
|
+
get hour() {
|
|
203
|
+
return this.$date.getHours();
|
|
186
204
|
}
|
|
187
|
-
|
|
188
|
-
return
|
|
205
|
+
setHour(v) {
|
|
206
|
+
return this.set('hour', v);
|
|
189
207
|
}
|
|
190
|
-
minute(
|
|
191
|
-
return
|
|
208
|
+
get minute() {
|
|
209
|
+
return this.$date.getMinutes();
|
|
192
210
|
}
|
|
193
|
-
|
|
194
|
-
return
|
|
211
|
+
setMinute(v) {
|
|
212
|
+
return this.set('minute', v);
|
|
213
|
+
}
|
|
214
|
+
get second() {
|
|
215
|
+
return this.$date.getSeconds();
|
|
216
|
+
}
|
|
217
|
+
setSecond(v) {
|
|
218
|
+
return this.set('second', v);
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Based on ISO: 1-7 is Mon-Sun.
|
|
222
|
+
*/
|
|
223
|
+
get dayOfWeek() {
|
|
224
|
+
return (this.$date.getDay() || 7);
|
|
225
|
+
}
|
|
226
|
+
setDayOfWeek(v) {
|
|
227
|
+
(0, assert_1._assert)(VALID_DAYS_OF_WEEK.has(v), `Invalid dayOfWeek: ${v}`);
|
|
228
|
+
const dow = this.$date.getDay() || 7;
|
|
229
|
+
return this.plus(v - dow, 'day');
|
|
195
230
|
}
|
|
196
231
|
setComponents(c, mutate = false) {
|
|
197
232
|
const d = mutate ? this.$date : new Date(this.$date);
|
|
@@ -259,7 +294,7 @@ class LocalTime {
|
|
|
259
294
|
}
|
|
260
295
|
if (unit === 'year' || unit === 'month') {
|
|
261
296
|
const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate);
|
|
262
|
-
return mutate ? this : exports.localTime.
|
|
297
|
+
return mutate ? this : exports.localTime.fromInput(d);
|
|
263
298
|
}
|
|
264
299
|
return this.set(unit, this.get(unit) + num, mutate);
|
|
265
300
|
}
|
|
@@ -270,7 +305,7 @@ class LocalTime {
|
|
|
270
305
|
return Math.abs(this.diff(other, unit));
|
|
271
306
|
}
|
|
272
307
|
diff(other, unit) {
|
|
273
|
-
const date2 = exports.localTime.
|
|
308
|
+
const date2 = exports.localTime.fromInput(other).$date;
|
|
274
309
|
const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
|
|
275
310
|
if (!secDiff)
|
|
276
311
|
return 0;
|
|
@@ -358,32 +393,32 @@ class LocalTime {
|
|
|
358
393
|
* Returns how many days are in the current month.
|
|
359
394
|
* E.g 31 for January.
|
|
360
395
|
*/
|
|
361
|
-
daysInMonth() {
|
|
396
|
+
get daysInMonth() {
|
|
362
397
|
return localDate_1.localDate.getMonthLength(this.$date.getFullYear(), this.$date.getMonth() + 1);
|
|
363
398
|
}
|
|
364
399
|
isSame(d) {
|
|
365
|
-
return this.
|
|
400
|
+
return this.compare(d) === 0;
|
|
366
401
|
}
|
|
367
402
|
isBefore(d, inclusive = false) {
|
|
368
|
-
const r = this.
|
|
403
|
+
const r = this.compare(d);
|
|
369
404
|
return r === -1 || (r === 0 && inclusive);
|
|
370
405
|
}
|
|
371
406
|
isSameOrBefore(d) {
|
|
372
|
-
return this.
|
|
407
|
+
return this.compare(d) <= 0;
|
|
373
408
|
}
|
|
374
409
|
isAfter(d, inclusive = false) {
|
|
375
|
-
const r = this.
|
|
410
|
+
const r = this.compare(d);
|
|
376
411
|
return r === 1 || (r === 0 && inclusive);
|
|
377
412
|
}
|
|
378
413
|
isSameOrAfter(d) {
|
|
379
|
-
return this.
|
|
414
|
+
return this.compare(d) >= 0;
|
|
380
415
|
}
|
|
381
416
|
isBetween(min, max, incl = '[)') {
|
|
382
|
-
let r = this.
|
|
417
|
+
let r = this.compare(min);
|
|
383
418
|
// eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
|
|
384
419
|
if (r < 0 || (r === 0 && incl[0] === '('))
|
|
385
420
|
return false;
|
|
386
|
-
r = this.
|
|
421
|
+
r = this.compare(max);
|
|
387
422
|
if (r > 0 || (r === 0 && incl[1] === ')'))
|
|
388
423
|
return false;
|
|
389
424
|
return true;
|
|
@@ -398,13 +433,13 @@ class LocalTime {
|
|
|
398
433
|
* Third argument allows to override "now".
|
|
399
434
|
*/
|
|
400
435
|
isOlderThan(n, unit, now) {
|
|
401
|
-
return this.isBefore(exports.localTime.
|
|
436
|
+
return this.isBefore(exports.localTime.fromInput(now ?? new Date()).plus(-n, unit));
|
|
402
437
|
}
|
|
403
438
|
/**
|
|
404
439
|
* Checks if this localTime is same or older (<=) than "now" by X units.
|
|
405
440
|
*/
|
|
406
441
|
isSameOrOlderThan(n, unit, now) {
|
|
407
|
-
return this.isSameOrBefore(exports.localTime.
|
|
442
|
+
return this.isSameOrBefore(exports.localTime.fromInput(now ?? new Date()).plus(-n, unit));
|
|
408
443
|
}
|
|
409
444
|
/**
|
|
410
445
|
* Checks if this localTime is younger (>) than "now" by X units.
|
|
@@ -416,13 +451,13 @@ class LocalTime {
|
|
|
416
451
|
* Third argument allows to override "now".
|
|
417
452
|
*/
|
|
418
453
|
isYoungerThan(n, unit, now) {
|
|
419
|
-
return this.isAfter(exports.localTime.
|
|
454
|
+
return this.isAfter(exports.localTime.fromInput(now ?? new Date()).plus(-n, unit));
|
|
420
455
|
}
|
|
421
456
|
/**
|
|
422
457
|
* Checks if this localTime is same or younger (>=) than "now" by X units.
|
|
423
458
|
*/
|
|
424
459
|
isSameOrYoungerThan(n, unit, now) {
|
|
425
|
-
return this.isSameOrAfter(exports.localTime.
|
|
460
|
+
return this.isSameOrAfter(exports.localTime.fromInput(now ?? new Date()).plus(-n, unit));
|
|
426
461
|
}
|
|
427
462
|
getAgeInYears(now) {
|
|
428
463
|
return this.getAgeIn('year', now);
|
|
@@ -443,42 +478,42 @@ class LocalTime {
|
|
|
443
478
|
return this.getAgeIn('second', now);
|
|
444
479
|
}
|
|
445
480
|
getAgeIn(unit, now) {
|
|
446
|
-
return exports.localTime.
|
|
481
|
+
return exports.localTime.fromInput(now ?? new Date()).diff(this, unit);
|
|
447
482
|
}
|
|
448
483
|
/**
|
|
449
484
|
* Returns 1 if this > d
|
|
450
485
|
* returns 0 if they are equal
|
|
451
486
|
* returns -1 if this < d
|
|
452
487
|
*/
|
|
453
|
-
|
|
488
|
+
compare(d) {
|
|
454
489
|
const t1 = this.$date.valueOf();
|
|
455
|
-
const t2 = exports.localTime.
|
|
490
|
+
const t2 = exports.localTime.fromInput(d).$date.valueOf();
|
|
456
491
|
if (t1 === t2)
|
|
457
492
|
return 0;
|
|
458
493
|
return t1 < t2 ? -1 : 1;
|
|
459
494
|
}
|
|
460
|
-
|
|
495
|
+
toDateTimeObject() {
|
|
461
496
|
return {
|
|
462
|
-
...this.
|
|
463
|
-
...this.
|
|
497
|
+
...this.toDateObject(),
|
|
498
|
+
...this.toTimeObject(),
|
|
464
499
|
};
|
|
465
500
|
}
|
|
466
|
-
|
|
501
|
+
toDateObject() {
|
|
467
502
|
return {
|
|
468
503
|
year: this.$date.getFullYear(),
|
|
469
504
|
month: this.$date.getMonth() + 1,
|
|
470
505
|
day: this.$date.getDate(),
|
|
471
506
|
};
|
|
472
507
|
}
|
|
473
|
-
|
|
508
|
+
toTimeObject() {
|
|
474
509
|
return {
|
|
475
510
|
hour: this.$date.getHours(),
|
|
476
511
|
minute: this.$date.getMinutes(),
|
|
477
512
|
second: this.$date.getSeconds(),
|
|
478
513
|
};
|
|
479
514
|
}
|
|
480
|
-
|
|
481
|
-
const msDiff = exports.localTime.
|
|
515
|
+
toFromNowString(now = new Date()) {
|
|
516
|
+
const msDiff = exports.localTime.fromInput(now).$date.valueOf() - this.$date.valueOf();
|
|
482
517
|
if (msDiff === 0)
|
|
483
518
|
return 'now';
|
|
484
519
|
if (msDiff >= 0) {
|
|
@@ -486,16 +521,16 @@ class LocalTime {
|
|
|
486
521
|
}
|
|
487
522
|
return `in ${(0, time_util_1._ms)(msDiff * -1)}`;
|
|
488
523
|
}
|
|
489
|
-
|
|
524
|
+
toDate() {
|
|
490
525
|
return this.$date;
|
|
491
526
|
}
|
|
492
527
|
clone() {
|
|
493
528
|
return new LocalTime(new Date(this.$date));
|
|
494
529
|
}
|
|
495
|
-
unix() {
|
|
530
|
+
get unix() {
|
|
496
531
|
return Math.floor(this.$date.valueOf() / 1000);
|
|
497
532
|
}
|
|
498
|
-
unixMillis() {
|
|
533
|
+
get unixMillis() {
|
|
499
534
|
return this.$date.valueOf();
|
|
500
535
|
}
|
|
501
536
|
valueOf() {
|
|
@@ -527,7 +562,7 @@ class LocalTime {
|
|
|
527
562
|
* Returns e.g: `1984-06-21`, only the date part of DateTime
|
|
528
563
|
*/
|
|
529
564
|
toISODate() {
|
|
530
|
-
const { year, month, day } = this.
|
|
565
|
+
const { year, month, day } = this.toDateObject();
|
|
531
566
|
return [
|
|
532
567
|
String(year).padStart(4, '0'),
|
|
533
568
|
String(month).padStart(2, '0'),
|
|
@@ -540,7 +575,7 @@ class LocalTime {
|
|
|
540
575
|
* Returns e.g: `17:03:15` (or `17:03` with seconds=false)
|
|
541
576
|
*/
|
|
542
577
|
toISOTime(seconds = true) {
|
|
543
|
-
const { hour, minute, second } = this.
|
|
578
|
+
const { hour, minute, second } = this.toTimeObject();
|
|
544
579
|
return [
|
|
545
580
|
String(hour).padStart(2, '0'),
|
|
546
581
|
String(minute).padStart(2, '0'),
|
|
@@ -555,7 +590,7 @@ class LocalTime {
|
|
|
555
590
|
* Returns e.g: `19840621_1705`
|
|
556
591
|
*/
|
|
557
592
|
toStringCompact(seconds = false) {
|
|
558
|
-
const { year, month, day, hour, minute, second } = this.
|
|
593
|
+
const { year, month, day, hour, minute, second } = this.toDateTimeObject();
|
|
559
594
|
return [
|
|
560
595
|
String(year).padStart(4, '0'),
|
|
561
596
|
String(month).padStart(2, '0'),
|
|
@@ -570,7 +605,7 @@ class LocalTime {
|
|
|
570
605
|
return this.toISODateTime();
|
|
571
606
|
}
|
|
572
607
|
toJSON() {
|
|
573
|
-
return this.unix
|
|
608
|
+
return this.unix;
|
|
574
609
|
}
|
|
575
610
|
toMonthId() {
|
|
576
611
|
return this.toISODate().slice(0, 7);
|
|
@@ -585,105 +620,198 @@ class LocalTime {
|
|
|
585
620
|
exports.LocalTime = LocalTime;
|
|
586
621
|
class LocalTimeFactory {
|
|
587
622
|
/**
|
|
588
|
-
*
|
|
589
|
-
*
|
|
623
|
+
* Creates a LocalTime from the input, unless it's falsy - then returns undefined.
|
|
624
|
+
*
|
|
625
|
+
* `localTime` function will instead return LocalTime of `now` for falsy input.
|
|
590
626
|
*/
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
(0, assert_1._assert)(t !== null, `Cannot parse "${d}" into LocalTime`, {
|
|
594
|
-
input: d,
|
|
595
|
-
});
|
|
596
|
-
return t;
|
|
627
|
+
orUndefined(input) {
|
|
628
|
+
return input || input === 0 ? this.fromInput(input) : undefined;
|
|
597
629
|
}
|
|
598
630
|
/**
|
|
599
|
-
*
|
|
631
|
+
* Creates a LocalTime from the input, unless it's falsy - then returns LocalTime.now
|
|
600
632
|
*/
|
|
601
|
-
|
|
602
|
-
return this.
|
|
633
|
+
orNow(input) {
|
|
634
|
+
return input || input === 0 ? this.fromInput(input) : this.now();
|
|
635
|
+
}
|
|
636
|
+
now() {
|
|
637
|
+
return new LocalTime(new Date());
|
|
603
638
|
}
|
|
604
639
|
/**
|
|
605
|
-
|
|
640
|
+
Convenience function to return current Unix timestamp in seconds.
|
|
641
|
+
Like Date.now(), but in seconds.
|
|
606
642
|
*/
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
return
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
// unexpected type, e.g Function or something
|
|
623
|
-
return null;
|
|
643
|
+
nowUnix() {
|
|
644
|
+
return Math.floor(Date.now() / 1000);
|
|
645
|
+
}
|
|
646
|
+
/**
|
|
647
|
+
* Create LocalTime from LocalTimeInput.
|
|
648
|
+
* Input can already be a LocalTime - it is returned as-is in that case.
|
|
649
|
+
* Date - will be used as-is.
|
|
650
|
+
* String - will be parsed as strict `yyyy-mm-ddThh:mm:ss`.
|
|
651
|
+
* Number - will be treated as unix timestamp in seconds.
|
|
652
|
+
*/
|
|
653
|
+
fromInput(input) {
|
|
654
|
+
if (input instanceof LocalTime)
|
|
655
|
+
return input;
|
|
656
|
+
if (input instanceof Date) {
|
|
657
|
+
return this.fromDate(input);
|
|
624
658
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
if (date === null)
|
|
628
|
-
return null;
|
|
659
|
+
if (typeof input === 'number') {
|
|
660
|
+
return this.fromUnix(input);
|
|
629
661
|
}
|
|
662
|
+
// It means it's a string
|
|
663
|
+
// Will parse it STRICTLY
|
|
664
|
+
return this.fromIsoDateTimeString(input);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* Returns true if input is valid to create LocalTime.
|
|
668
|
+
*/
|
|
669
|
+
isValid(input) {
|
|
670
|
+
if (!input)
|
|
671
|
+
return false;
|
|
672
|
+
if (input instanceof LocalTime)
|
|
673
|
+
return true;
|
|
674
|
+
if (input instanceof Date)
|
|
675
|
+
return !isNaN(input.getDate());
|
|
676
|
+
// We currently don't validate Unixtimestamp input, treat it as always valid
|
|
677
|
+
if (typeof input === 'number')
|
|
678
|
+
return true;
|
|
679
|
+
return this.isValidString(input);
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Returns true if isoString is a valid iso8601 string like `yyyy-mm-ddThh:mm:dd`.
|
|
683
|
+
*/
|
|
684
|
+
isValidString(isoString) {
|
|
685
|
+
return !!this.parseStrictlyOrUndefined(isoString);
|
|
686
|
+
}
|
|
687
|
+
/**
|
|
688
|
+
* Tries to convert/parse the input into LocalTime.
|
|
689
|
+
* Uses LOOSE parsing.
|
|
690
|
+
* If invalid - doesn't throw, but returns undefined instead.
|
|
691
|
+
*/
|
|
692
|
+
try(input) {
|
|
693
|
+
if (input instanceof LocalTime)
|
|
694
|
+
return input;
|
|
695
|
+
if (input instanceof Date) {
|
|
696
|
+
if (isNaN(input.getDate()))
|
|
697
|
+
return;
|
|
698
|
+
return new LocalTime(input);
|
|
699
|
+
}
|
|
700
|
+
if (typeof input === 'number') {
|
|
701
|
+
return this.fromUnix(input);
|
|
702
|
+
}
|
|
703
|
+
if (!input)
|
|
704
|
+
return;
|
|
705
|
+
const date = this.parseLooselyOrUndefined(input);
|
|
706
|
+
return date ? new LocalTime(date) : undefined;
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Performs STRICT parsing.
|
|
710
|
+
* Only allows IsoDateTimeString or IsoDateString input, nothing else.
|
|
711
|
+
*/
|
|
712
|
+
// eslint-disable-next-line @typescript-eslint/no-duplicate-type-constituents
|
|
713
|
+
fromIsoDateTimeString(s) {
|
|
714
|
+
const d = this.parseStrictlyOrUndefined(s);
|
|
715
|
+
(0, assert_1._assert)(d, `Cannot parse "${s}" into LocalTime`);
|
|
716
|
+
return new LocalTime(d);
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Performs LOOSE parsing.
|
|
720
|
+
* Tries to coerce imprefect/incorrect string input into IsoDateTimeString.
|
|
721
|
+
* Use with caution.
|
|
722
|
+
* Allows to input IsoDateString, will set h:m:s to zeros.
|
|
723
|
+
*/
|
|
724
|
+
parse(s) {
|
|
725
|
+
const d = this.parseLooselyOrUndefined(String(s));
|
|
726
|
+
(0, assert_1._assert)(d, `Cannot parse "${s}" into LocalTime`);
|
|
727
|
+
return new LocalTime(d);
|
|
728
|
+
}
|
|
729
|
+
parseStrictlyOrUndefined(s) {
|
|
730
|
+
if (!s || typeof s !== 'string')
|
|
731
|
+
return;
|
|
732
|
+
let m = DATE_TIME_REGEX_STRICT.exec(s);
|
|
733
|
+
if (!m) {
|
|
734
|
+
// DateTime regex didn't match, try just-Date regex
|
|
735
|
+
m = DATE_REGEX_STRICT.exec(s);
|
|
736
|
+
if (!m)
|
|
737
|
+
return;
|
|
738
|
+
}
|
|
739
|
+
const o = {
|
|
740
|
+
year: Number(m[1]),
|
|
741
|
+
month: Number(m[2]),
|
|
742
|
+
day: Number(m[3]),
|
|
743
|
+
hour: Number(m[4]) || 0,
|
|
744
|
+
minute: Number(m[5]) || 0,
|
|
745
|
+
second: Number(m[6]) || 0,
|
|
746
|
+
};
|
|
747
|
+
if (!this.isDateTimeObjectValid(o))
|
|
748
|
+
return;
|
|
749
|
+
return this.createDateFromDateTimeObject(o);
|
|
750
|
+
}
|
|
751
|
+
parseLooselyOrUndefined(s) {
|
|
752
|
+
if (!s || typeof s !== 'string')
|
|
753
|
+
return;
|
|
754
|
+
const m = DATE_TIME_REGEX_LOOSE.exec(s);
|
|
755
|
+
if (!m) {
|
|
756
|
+
if (s.length < 8)
|
|
757
|
+
return;
|
|
758
|
+
// Attempt to parse with Date constructor
|
|
759
|
+
const d = new Date(s);
|
|
760
|
+
return isNaN(d.getDate()) ? undefined : d;
|
|
761
|
+
}
|
|
762
|
+
const o = {
|
|
763
|
+
year: Number(m[1]),
|
|
764
|
+
month: Number(m[2]),
|
|
765
|
+
day: Number(m[3]) || 1,
|
|
766
|
+
// [4] is skipped due to extra regex parentheses group
|
|
767
|
+
hour: Number(m[5]) || 0,
|
|
768
|
+
minute: Number(m[6]) || 0,
|
|
769
|
+
second: Number(m[7]) || 0,
|
|
770
|
+
};
|
|
771
|
+
if (!this.isDateTimeObjectValid(o))
|
|
772
|
+
return;
|
|
773
|
+
return this.createDateFromDateTimeObject(o);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Throws on invalid value.
|
|
777
|
+
*/
|
|
778
|
+
validateDateTimeObject(o) {
|
|
779
|
+
(0, assert_1._assert)(this.isDateTimeObjectValid(o), `Cannot construct LocalTime from: ${o.year}-${o.month}-${o.day} ${o.hour}:${o.minute}:${o.second}`);
|
|
780
|
+
}
|
|
781
|
+
isDateTimeObjectValid(o) {
|
|
782
|
+
return localDate_1.localDate.isDateObjectValid(o) && this.isTimeObjectValid(o);
|
|
783
|
+
}
|
|
784
|
+
isTimeObjectValid({ hour, minute, second }) {
|
|
785
|
+
return hour >= 0 && hour <= 23 && minute >= 0 && minute <= 59 && second >= 0 && second <= 59;
|
|
786
|
+
}
|
|
787
|
+
fromDate(date) {
|
|
788
|
+
(0, assert_1._assert)(!isNaN(date.getDate()), `localTime.fromDate is called on Date object that is invalid`);
|
|
630
789
|
return new LocalTime(date);
|
|
631
790
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
// e.g 2022-04-06T23:15:00+09:00
|
|
635
|
-
// becomes 2022-04-06T23:15:00
|
|
636
|
-
// date = new Date(d.slice(0, 19))
|
|
637
|
-
// Parsing is inspired by how Day.js does it
|
|
638
|
-
// Specifically, it ensures that `localTime('2023-03-03')` returns the expected Date, and not a day before
|
|
639
|
-
// Because `new Date('2023-03-03')` in NewYork gives you '2023-03-02 19:00:00 GMT-0500'
|
|
640
|
-
const m = s.match(DATE_TIME_REGEX);
|
|
641
|
-
// Validate in 3 ways:
|
|
642
|
-
// 1. Should match Regex.
|
|
643
|
-
// In some ways it's stricter than Date constructor, e.g it doesn't allow 2023/05/05
|
|
644
|
-
// In other ways it's looser, e.g it allows `2023-05-05T`, while Date constructor doesn't.
|
|
645
|
-
// 2. Date constructor (of Node/v8 implementation, which we know is different from e.g WebKit/Safari)
|
|
646
|
-
// should not return `Invalid Date`.
|
|
647
|
-
// 3. Year, month and day should be valid, e.g 2023-01-32 should not be allowed.
|
|
648
|
-
// UPD: Actually, 3 can be skipped, because 2 is catching it already
|
|
649
|
-
// UPD: 2 is skipped, 1 and 3 are kept
|
|
650
|
-
// if (!m || isNaN(new Date(s).getDate())) return null
|
|
651
|
-
if (!m)
|
|
652
|
-
return null;
|
|
653
|
-
const year = Number(m[1]);
|
|
654
|
-
const month = Number(m[2]);
|
|
655
|
-
const day = Number(m[3]);
|
|
656
|
-
const hour = Number(m[5]);
|
|
657
|
-
const minute = Number(m[6]);
|
|
658
|
-
const second = Number(m[7]);
|
|
659
|
-
// Validation for just the Date part
|
|
660
|
-
if (!year ||
|
|
661
|
-
!month ||
|
|
662
|
-
month < 1 ||
|
|
663
|
-
month > 12 ||
|
|
664
|
-
!day ||
|
|
665
|
-
day < 1 ||
|
|
666
|
-
day > localDate_1.localDate.getMonthLength(year, month)) {
|
|
667
|
-
return null;
|
|
668
|
-
}
|
|
669
|
-
// Validation for Date+Time string, since the string is longer than YYYY-MM-DD
|
|
670
|
-
if (s.length > 10 &&
|
|
671
|
-
(isNaN(hour) ||
|
|
672
|
-
isNaN(minute) ||
|
|
673
|
-
isNaN(second) ||
|
|
674
|
-
hour < 0 ||
|
|
675
|
-
hour > 23 ||
|
|
676
|
-
minute < 0 ||
|
|
677
|
-
minute > 59 ||
|
|
678
|
-
second < 0 ||
|
|
679
|
-
second > 59)) {
|
|
680
|
-
return null;
|
|
681
|
-
}
|
|
682
|
-
return new Date(year, month - 1, day, hour || 0, minute || 0, second || 0, 0);
|
|
683
|
-
}
|
|
684
|
-
isValid(d) {
|
|
685
|
-
return this.parseOrNull(d) !== null;
|
|
791
|
+
fromUnix(ts) {
|
|
792
|
+
return new LocalTime(new Date(ts * 1000));
|
|
686
793
|
}
|
|
794
|
+
/**
|
|
795
|
+
* Create LocalTime from unixTimestamp in milliseconds (not in seconds).
|
|
796
|
+
*/
|
|
797
|
+
fromMillis(millis) {
|
|
798
|
+
return new LocalTime(new Date(millis));
|
|
799
|
+
}
|
|
800
|
+
fromDateTimeObject(o) {
|
|
801
|
+
// todo: validate?
|
|
802
|
+
return new LocalTime(this.createDateFromDateTimeObject(o));
|
|
803
|
+
}
|
|
804
|
+
createDateFromDateTimeObject(o) {
|
|
805
|
+
return new Date(o.year, o.month - 1, o.day || 1, o.hour || 0, o.minute || 0, o.second || 0);
|
|
806
|
+
}
|
|
807
|
+
// private assertNotNull(
|
|
808
|
+
// lt: LocalTime | null,
|
|
809
|
+
// input: LocalTimeInputNullable,
|
|
810
|
+
// ): asserts lt is LocalTime {
|
|
811
|
+
// _assert(lt !== null, `Cannot parse "${input}" into LocalTime`, {
|
|
812
|
+
// input,
|
|
813
|
+
// })
|
|
814
|
+
// }
|
|
687
815
|
/**
|
|
688
816
|
* Returns the IANA timezone e.g `Europe/Stockholm`.
|
|
689
817
|
* https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
|
@@ -701,26 +829,6 @@ class LocalTimeFactory {
|
|
|
701
829
|
isTimezoneValid(tz) {
|
|
702
830
|
return Intl.supportedValuesOf('timeZone').includes(tz);
|
|
703
831
|
}
|
|
704
|
-
now() {
|
|
705
|
-
return new LocalTime(new Date());
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Creates a LocalTime from the input, unless it's falsy - then returns undefined.
|
|
709
|
-
*
|
|
710
|
-
* `localTime` function will instead return LocalTime of `now` for falsy input.
|
|
711
|
-
*/
|
|
712
|
-
orUndefined(d) {
|
|
713
|
-
return d ? this.of(d) : undefined;
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Creates a LocalTime from the input, unless it's falsy - then returns LocalTime.now
|
|
717
|
-
*/
|
|
718
|
-
orNow(d) {
|
|
719
|
-
return d ? this.of(d) : this.now();
|
|
720
|
-
}
|
|
721
|
-
fromComponents(c) {
|
|
722
|
-
return new LocalTime(new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0));
|
|
723
|
-
}
|
|
724
832
|
sort(items, dir = 'asc', mutate = false) {
|
|
725
833
|
const mod = dir === 'desc' ? -1 : 1;
|
|
726
834
|
return (mutate ? items : [...items]).sort((a, b) => {
|
|
@@ -738,7 +846,7 @@ class LocalTimeFactory {
|
|
|
738
846
|
const items2 = items.filter(is_util_1._isTruthy);
|
|
739
847
|
(0, assert_1._assert)(items2.length, 'localTime.min called on empty array');
|
|
740
848
|
return items2
|
|
741
|
-
.map(i => this.
|
|
849
|
+
.map(i => this.fromInput(i))
|
|
742
850
|
.reduce((min, item) => (min.$date.valueOf() <= item.$date.valueOf() ? min : item));
|
|
743
851
|
}
|
|
744
852
|
maxOrUndefined(items) {
|
|
@@ -748,7 +856,7 @@ class LocalTimeFactory {
|
|
|
748
856
|
const items2 = items.filter(is_util_1._isTruthy);
|
|
749
857
|
(0, assert_1._assert)(items2.length, 'localTime.max called on empty array');
|
|
750
858
|
return items2
|
|
751
|
-
.map(i => this.
|
|
859
|
+
.map(i => this.fromInput(i))
|
|
752
860
|
.reduce((max, item) => (max.$date.valueOf() >= item.$date.valueOf() ? max : item));
|
|
753
861
|
}
|
|
754
862
|
}
|
|
@@ -841,14 +949,7 @@ function differenceInMonths(a, b) {
|
|
|
841
949
|
return -(wholeMonthDiff + ((b.getTime() - anchor) / (anchor2 - anchor)) * sign);
|
|
842
950
|
}
|
|
843
951
|
const localTimeFactory = new LocalTimeFactory();
|
|
844
|
-
exports.localTime = localTimeFactory.
|
|
952
|
+
exports.localTime = localTimeFactory.fromInput.bind(localTimeFactory);
|
|
845
953
|
// The line below is the blackest of black magic I have ever written in 2024.
|
|
846
954
|
// And probably 2023 as well.
|
|
847
955
|
Object.setPrototypeOf(exports.localTime, localTimeFactory);
|
|
848
|
-
/**
|
|
849
|
-
Convenience function to return current Unix timestamp in seconds.
|
|
850
|
-
Like Date.now(), but in seconds.
|
|
851
|
-
*/
|
|
852
|
-
function nowUnix() {
|
|
853
|
-
return Math.floor(Date.now() / 1000);
|
|
854
|
-
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import {
|
|
1
|
+
import type { Inclusiveness, UnixTimestampNumber } from '../types';
|
|
2
|
+
import { LocalTime, LocalTimeInput } from './localTime';
|
|
3
3
|
export type TimeIntervalConfig = TimeInterval | TimeIntervalString;
|
|
4
4
|
export type TimeIntervalString = string;
|
|
5
5
|
/**
|