@naturalcycles/js-lib 14.243.0 → 14.244.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.
@@ -19,6 +19,10 @@ const SECONDS_IN_DAY = 86400;
19
19
  // const MILLISECONDS_IN_DAY = 86400000
20
20
  // const MILLISECONDS_IN_MINUTE = 60000
21
21
  const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
22
+ // It supports 2 forms:
23
+ // 1. 2023-03-03
24
+ // 2. 2023-03-03T05:10:02
25
+ const DATE_TIME_REGEX = /^(\d{4})-(\d{2})-(\d{2})([T\s](\d{2}):(\d{2}):(\d{2}))?/;
22
26
  export class LocalTime {
23
27
  constructor($date) {
24
28
  this.$date = $date;
@@ -27,14 +31,14 @@ export class LocalTime {
27
31
  * Returns [cloned] LocalTime that is based on the same unixtimestamp, but in UTC timezone.
28
32
  * Opposite of `.local()` method.
29
33
  */
30
- utc() {
34
+ toUTC() {
31
35
  return new LocalTime(new Date(this.$date.toISOString()));
32
36
  }
33
37
  /**
34
38
  * Returns [cloned] LocalTime that is based on the same unixtimestamp, but in local timezone.
35
39
  * Opposite of `.utc()` method.
36
40
  */
37
- local() {
41
+ toLocal() {
38
42
  return new LocalTime(new Date(this.$date.getTime()));
39
43
  }
40
44
  /**
@@ -156,34 +160,58 @@ export class LocalTime {
156
160
  }
157
161
  return t;
158
162
  }
159
- year(v) {
160
- return v === undefined ? this.get('year') : this.set('year', v);
163
+ get year() {
164
+ return this.$date.getFullYear();
161
165
  }
162
- month(v) {
163
- return v === undefined ? this.get('month') : this.set('month', v);
166
+ setYear(v) {
167
+ return this.set('year', v);
164
168
  }
165
- week(v) {
166
- return v === undefined ? getWeek(this.$date) : this.set('week', v);
169
+ get month() {
170
+ return this.$date.getMonth() + 1;
167
171
  }
168
- day(v) {
169
- return v === undefined ? this.get('day') : this.set('day', v);
172
+ setMonth(v) {
173
+ return this.set('month', v);
170
174
  }
171
- dayOfWeek(v) {
172
- const dow = (this.$date.getDay() || 7);
173
- if (v === undefined) {
174
- return dow;
175
- }
176
- _assert(VALID_DAYS_OF_WEEK.has(v), `Invalid dayOfWeek: ${v}`);
177
- return this.plus(v - dow, 'day');
175
+ get week() {
176
+ return getWeek(this.$date);
177
+ }
178
+ setWeek(v) {
179
+ return this.set('week', v);
180
+ }
181
+ get day() {
182
+ return this.$date.getDate();
178
183
  }
179
- hour(v) {
180
- return v === undefined ? this.get('hour') : this.set('hour', v);
184
+ setDay(v) {
185
+ return this.set('day', v);
181
186
  }
182
- minute(v) {
183
- return v === undefined ? this.get('minute') : this.set('minute', v);
187
+ get hour() {
188
+ return this.$date.getHours();
189
+ }
190
+ setHour(v) {
191
+ return this.set('hour', v);
192
+ }
193
+ get minute() {
194
+ return this.$date.getMinutes();
195
+ }
196
+ setMinute(v) {
197
+ return this.set('minute', v);
198
+ }
199
+ get second() {
200
+ return this.$date.getSeconds();
184
201
  }
185
- second(v) {
186
- return v === undefined ? this.get('second') : this.set('second', v);
202
+ setSecond(v) {
203
+ return this.set('second', v);
204
+ }
205
+ /**
206
+ * Based on ISO: 1-7 is Mon-Sun.
207
+ */
208
+ get dayOfWeek() {
209
+ return (this.$date.getDay() || 7);
210
+ }
211
+ setDayOfWeek(v) {
212
+ _assert(VALID_DAYS_OF_WEEK.has(v), `Invalid dayOfWeek: ${v}`);
213
+ const dow = this.$date.getDay() || 7;
214
+ return this.plus(v - dow, 'day');
187
215
  }
188
216
  setComponents(c, mutate = false) {
189
217
  const d = mutate ? this.$date : new Date(this.$date);
@@ -251,7 +279,7 @@ export class LocalTime {
251
279
  }
252
280
  if (unit === 'year' || unit === 'month') {
253
281
  const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate);
254
- return mutate ? this : localTime.of(d);
282
+ return mutate ? this : localTime.from(d);
255
283
  }
256
284
  return this.set(unit, this.get(unit) + num, mutate);
257
285
  }
@@ -262,7 +290,7 @@ export class LocalTime {
262
290
  return Math.abs(this.diff(other, unit));
263
291
  }
264
292
  diff(other, unit) {
265
- const date2 = localTime.parseToDate(other);
293
+ const date2 = localTime.from(other).$date;
266
294
  const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
267
295
  if (!secDiff)
268
296
  return 0;
@@ -350,32 +378,32 @@ export class LocalTime {
350
378
  * Returns how many days are in the current month.
351
379
  * E.g 31 for January.
352
380
  */
353
- daysInMonth() {
381
+ get daysInMonth() {
354
382
  return localDate.getMonthLength(this.$date.getFullYear(), this.$date.getMonth() + 1);
355
383
  }
356
384
  isSame(d) {
357
- return this.cmp(d) === 0;
385
+ return this.compare(d) === 0;
358
386
  }
359
387
  isBefore(d, inclusive = false) {
360
- const r = this.cmp(d);
388
+ const r = this.compare(d);
361
389
  return r === -1 || (r === 0 && inclusive);
362
390
  }
363
391
  isSameOrBefore(d) {
364
- return this.cmp(d) <= 0;
392
+ return this.compare(d) <= 0;
365
393
  }
366
394
  isAfter(d, inclusive = false) {
367
- const r = this.cmp(d);
395
+ const r = this.compare(d);
368
396
  return r === 1 || (r === 0 && inclusive);
369
397
  }
370
398
  isSameOrAfter(d) {
371
- return this.cmp(d) >= 0;
399
+ return this.compare(d) >= 0;
372
400
  }
373
401
  isBetween(min, max, incl = '[)') {
374
- let r = this.cmp(min);
402
+ let r = this.compare(min);
375
403
  // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
376
404
  if (r < 0 || (r === 0 && incl[0] === '('))
377
405
  return false;
378
- r = this.cmp(max);
406
+ r = this.compare(max);
379
407
  if (r > 0 || (r === 0 && incl[1] === ')'))
380
408
  return false;
381
409
  return true;
@@ -390,13 +418,13 @@ export class LocalTime {
390
418
  * Third argument allows to override "now".
391
419
  */
392
420
  isOlderThan(n, unit, now) {
393
- return this.isBefore(localTime.of(now ?? new Date()).plus(-n, unit));
421
+ return this.isBefore(localTime.from(now ?? new Date()).plus(-n, unit));
394
422
  }
395
423
  /**
396
424
  * Checks if this localTime is same or older (<=) than "now" by X units.
397
425
  */
398
426
  isSameOrOlderThan(n, unit, now) {
399
- return this.isSameOrBefore(localTime.of(now ?? new Date()).plus(-n, unit));
427
+ return this.isSameOrBefore(localTime.from(now ?? new Date()).plus(-n, unit));
400
428
  }
401
429
  /**
402
430
  * Checks if this localTime is younger (>) than "now" by X units.
@@ -408,13 +436,13 @@ export class LocalTime {
408
436
  * Third argument allows to override "now".
409
437
  */
410
438
  isYoungerThan(n, unit, now) {
411
- return this.isAfter(localTime.of(now ?? new Date()).plus(-n, unit));
439
+ return this.isAfter(localTime.from(now ?? new Date()).plus(-n, unit));
412
440
  }
413
441
  /**
414
442
  * Checks if this localTime is same or younger (>=) than "now" by X units.
415
443
  */
416
444
  isSameOrYoungerThan(n, unit, now) {
417
- return this.isSameOrAfter(localTime.of(now ?? new Date()).plus(-n, unit));
445
+ return this.isSameOrAfter(localTime.from(now ?? new Date()).plus(-n, unit));
418
446
  }
419
447
  getAgeInYears(now) {
420
448
  return this.getAgeIn('year', now);
@@ -435,42 +463,42 @@ export class LocalTime {
435
463
  return this.getAgeIn('second', now);
436
464
  }
437
465
  getAgeIn(unit, now) {
438
- return localTime.of(now ?? new Date()).diff(this, unit);
466
+ return localTime.from(now ?? new Date()).diff(this, unit);
439
467
  }
440
468
  /**
441
469
  * Returns 1 if this > d
442
470
  * returns 0 if they are equal
443
471
  * returns -1 if this < d
444
472
  */
445
- cmp(d) {
473
+ compare(d) {
446
474
  const t1 = this.$date.valueOf();
447
- const t2 = localTime.parseToDate(d).valueOf();
475
+ const t2 = localTime.from(d).$date.valueOf();
448
476
  if (t1 === t2)
449
477
  return 0;
450
478
  return t1 < t2 ? -1 : 1;
451
479
  }
452
- getDateTimeObject() {
480
+ toDateTimeObject() {
453
481
  return {
454
- ...this.getDateObject(),
455
- ...this.getTimeObject(),
482
+ ...this.toDateObject(),
483
+ ...this.toTimeObject(),
456
484
  };
457
485
  }
458
- getDateObject() {
486
+ toDateObject() {
459
487
  return {
460
488
  year: this.$date.getFullYear(),
461
489
  month: this.$date.getMonth() + 1,
462
490
  day: this.$date.getDate(),
463
491
  };
464
492
  }
465
- getTimeObject() {
493
+ toTimeObject() {
466
494
  return {
467
495
  hour: this.$date.getHours(),
468
496
  minute: this.$date.getMinutes(),
469
497
  second: this.$date.getSeconds(),
470
498
  };
471
499
  }
472
- fromNow(now = new Date()) {
473
- const msDiff = localTime.parseToDate(now).valueOf() - this.$date.valueOf();
500
+ toFromNowString(now = new Date()) {
501
+ const msDiff = localTime.from(now).$date.valueOf() - this.$date.valueOf();
474
502
  if (msDiff === 0)
475
503
  return 'now';
476
504
  if (msDiff >= 0) {
@@ -478,16 +506,16 @@ export class LocalTime {
478
506
  }
479
507
  return `in ${_ms(msDiff * -1)}`;
480
508
  }
481
- getDate() {
509
+ toDate() {
482
510
  return this.$date;
483
511
  }
484
512
  clone() {
485
513
  return new LocalTime(new Date(this.$date));
486
514
  }
487
- unix() {
515
+ get unix() {
488
516
  return Math.floor(this.$date.valueOf() / 1000);
489
517
  }
490
- unixMillis() {
518
+ get unixMillis() {
491
519
  return this.$date.valueOf();
492
520
  }
493
521
  valueOf() {
@@ -519,7 +547,7 @@ export class LocalTime {
519
547
  * Returns e.g: `1984-06-21`, only the date part of DateTime
520
548
  */
521
549
  toISODate() {
522
- const { year, month, day } = this.getDateObject();
550
+ const { year, month, day } = this.toDateObject();
523
551
  return [
524
552
  String(year).padStart(4, '0'),
525
553
  String(month).padStart(2, '0'),
@@ -532,7 +560,7 @@ export class LocalTime {
532
560
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
533
561
  */
534
562
  toISOTime(seconds = true) {
535
- const { hour, minute, second } = this.getTimeObject();
563
+ const { hour, minute, second } = this.toTimeObject();
536
564
  return [
537
565
  String(hour).padStart(2, '0'),
538
566
  String(minute).padStart(2, '0'),
@@ -547,7 +575,7 @@ export class LocalTime {
547
575
  * Returns e.g: `19840621_1705`
548
576
  */
549
577
  toStringCompact(seconds = false) {
550
- const { year, month, day, hour, minute, second } = this.getDateTimeObject();
578
+ const { year, month, day, hour, minute, second } = this.toDateTimeObject();
551
579
  return [
552
580
  String(year).padStart(4, '0'),
553
581
  String(month).padStart(2, '0'),
@@ -562,7 +590,7 @@ export class LocalTime {
562
590
  return this.toISODateTime();
563
591
  }
564
592
  toJSON() {
565
- return this.unix();
593
+ return this.unix;
566
594
  }
567
595
  toMonthId() {
568
596
  return this.toISODate().slice(0, 7);
@@ -576,82 +604,117 @@ export class LocalTime {
576
604
  }
577
605
  class LocalTimeFactory {
578
606
  /**
579
- * Parses input String into LocalDate.
580
- * Input can already be a LocalDate - it is returned as-is in that case.
607
+ * Parses input String into LocalTime.
608
+ * Input can already be a LocalTime - it is returned as-is in that case.
581
609
  */
582
- of(d) {
583
- const t = this.parseOrNull(d);
584
- _assert(t !== null, `Cannot parse "${d}" into LocalTime`, {
585
- input: d,
586
- });
587
- return t;
610
+ from(input) {
611
+ const lt = this.fromOrNull(input);
612
+ this.assertNotNull(lt, input);
613
+ return lt;
614
+ }
615
+ fromDate(date) {
616
+ return new LocalTime(date);
617
+ }
618
+ fromUnix(ts) {
619
+ return new LocalTime(new Date(ts * 1000));
588
620
  }
589
621
  /**
590
622
  * Create LocalTime from unixTimestamp in milliseconds (not in seconds).
591
623
  */
592
- ofMillis(millis) {
593
- return this.of(new Date(millis));
624
+ fromMillis(millis) {
625
+ return new LocalTime(new Date(millis));
594
626
  }
595
627
  /**
596
628
  * Returns null if invalid
597
629
  */
598
- parseOrNull(d) {
630
+ fromOrNull(d) {
599
631
  if (d instanceof LocalTime)
600
632
  return d;
601
- let date;
602
633
  if (d instanceof Date) {
603
- date = d;
634
+ return new LocalTime(d);
604
635
  }
605
- else if (typeof d === 'number') {
606
- date = new Date(d * 1000);
636
+ if (typeof d === 'number') {
637
+ return new LocalTime(new Date(d * 1000));
607
638
  }
608
- else if (!d) {
609
- // This check is after checking the number, to support `0`
610
- return null;
639
+ if (typeof d === 'string') {
640
+ return this.fromStringOrNull(d);
611
641
  }
612
- else if (typeof d !== 'string') {
613
- // unexpected type, e.g Function or something
642
+ // This check is after checking the number, to support `0`
643
+ // unexpected type, e.g Function or something
644
+ return null;
645
+ }
646
+ fromStringOrNull(s) {
647
+ const date = this.parseStringToDateOrNull(s);
648
+ return date ? new LocalTime(date) : null;
649
+ }
650
+ fromDateTimeObject(input) {
651
+ const { year, month, day = 1, hour = 0, minute = 0, second = 0 } = input;
652
+ return new LocalTime(new Date(year, month - 1, day, hour, minute, second));
653
+ }
654
+ parseStringToDateOrNull(s) {
655
+ if (!s)
656
+ return null;
657
+ // Slicing removes the "timezone component", and makes the date "local"
658
+ // e.g 2022-04-06T23:15:00+09:00
659
+ // becomes 2022-04-06T23:15:00
660
+ // date = new Date(d.slice(0, 19))
661
+ // Parsing is inspired by how Day.js does it
662
+ // Specifically, it ensures that `localTime('2023-03-03')` returns the expected Date, and not a day before
663
+ // Because `new Date('2023-03-03')` in NewYork gives you '2023-03-02 19:00:00 GMT-0500'
664
+ const m = s.match(DATE_TIME_REGEX);
665
+ // Validate in 3 ways:
666
+ // 1. Should match Regex.
667
+ // In some ways it's stricter than Date constructor, e.g it doesn't allow 2023/05/05
668
+ // In other ways it's looser, e.g it allows `2023-05-05T`, while Date constructor doesn't.
669
+ // 2. Date constructor (of Node/v8 implementation, which we know is different from e.g WebKit/Safari)
670
+ // should not return `Invalid Date`.
671
+ // 3. Year, month and day should be valid, e.g 2023-01-32 should not be allowed.
672
+ // UPD: Actually, 3 can be skipped, because 2 is catching it already
673
+ // UPD: 2 is skipped, 1 and 3 are kept
674
+ // if (!m || isNaN(new Date(s).getDate())) return null
675
+ if (!m)
676
+ return null;
677
+ const year = Number(m[1]);
678
+ const month = Number(m[2]);
679
+ const day = Number(m[3]);
680
+ const hour = Number(m[5]);
681
+ const minute = Number(m[6]);
682
+ const second = Number(m[7]);
683
+ // Validation for just the Date part
684
+ if (!year ||
685
+ !month ||
686
+ month < 1 ||
687
+ month > 12 ||
688
+ !day ||
689
+ day < 1 ||
690
+ day > localDate.getMonthLength(year, month)) {
614
691
  return null;
615
692
  }
616
- else {
617
- // Slicing removes the "timezone component", and makes the date "local"
618
- // e.g 2022-04-06T23:15:00+09:00
619
- // becomes 2022-04-06T23:15:00
620
- date = new Date(d.slice(0, 19));
621
- // We used to slice to remove the timezone information, now we don't
622
- // date = new Date(d)
623
- }
624
- // validation
625
- if (isNaN(date.getDate())) {
626
- // throw new TypeError(`Cannot parse "${d}" into LocalTime`)
693
+ // Validation for Date+Time string, since the string is longer than YYYY-MM-DD
694
+ if (s.length > 10 &&
695
+ (isNaN(hour) ||
696
+ isNaN(minute) ||
697
+ isNaN(second) ||
698
+ hour < 0 ||
699
+ hour > 23 ||
700
+ minute < 0 ||
701
+ minute > 59 ||
702
+ second < 0 ||
703
+ second > 59)) {
627
704
  return null;
628
705
  }
629
- return new LocalTime(date);
706
+ return new Date(year, month - 1, day, hour || 0, minute || 0, second || 0, 0);
630
707
  }
631
- parseToDate(d) {
632
- if (d instanceof LocalTime)
633
- return d.$date;
634
- if (d instanceof Date)
635
- return d;
636
- const date = typeof d === 'number' ? new Date(d * 1000) : new Date(d);
637
- _assert(!isNaN(date.getDate()), `Cannot parse "${d}" to Date`, {
638
- input: d,
639
- });
640
- return date;
708
+ isValid(input) {
709
+ return this.fromOrNull(input) !== null;
641
710
  }
642
- parseToUnixTimestamp(d) {
643
- if (typeof d === 'number')
644
- return d;
645
- if (d instanceof LocalTime)
646
- return d.unix();
647
- const date = d instanceof Date ? d : new Date(d);
648
- _assert(!isNaN(date.getDate()), `Cannot parse "${d}" to UnixTimestamp`, {
649
- input: d,
650
- });
651
- return date.valueOf() / 1000;
711
+ isValidString(isoString) {
712
+ return this.fromStringOrNull(isoString) !== null;
652
713
  }
653
- isValid(d) {
654
- return this.parseOrNull(d) !== null;
714
+ assertNotNull(lt, input) {
715
+ _assert(lt !== null, `Cannot parse "${input}" into LocalTime`, {
716
+ input,
717
+ });
655
718
  }
656
719
  /**
657
720
  * Returns the IANA timezone e.g `Europe/Stockholm`.
@@ -678,17 +741,14 @@ class LocalTimeFactory {
678
741
  *
679
742
  * `localTime` function will instead return LocalTime of `now` for falsy input.
680
743
  */
681
- orUndefined(d) {
682
- return d ? this.of(d) : undefined;
744
+ orUndefined(input) {
745
+ return input || input === 0 ? this.from(input) : undefined;
683
746
  }
684
747
  /**
685
748
  * Creates a LocalTime from the input, unless it's falsy - then returns LocalTime.now
686
749
  */
687
- orNow(d) {
688
- return d ? this.of(d) : this.now();
689
- }
690
- fromComponents(c) {
691
- return new LocalTime(new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0));
750
+ orNow(input) {
751
+ return input || input === 0 ? this.from(input) : this.now();
692
752
  }
693
753
  sort(items, dir = 'asc', mutate = false) {
694
754
  const mod = dir === 'desc' ? -1 : 1;
@@ -707,7 +767,7 @@ class LocalTimeFactory {
707
767
  const items2 = items.filter(_isTruthy);
708
768
  _assert(items2.length, 'localTime.min called on empty array');
709
769
  return items2
710
- .map(i => this.of(i))
770
+ .map(i => this.from(i))
711
771
  .reduce((min, item) => (min.$date.valueOf() <= item.$date.valueOf() ? min : item));
712
772
  }
713
773
  maxOrUndefined(items) {
@@ -717,7 +777,7 @@ class LocalTimeFactory {
717
777
  const items2 = items.filter(_isTruthy);
718
778
  _assert(items2.length, 'localTime.max called on empty array');
719
779
  return items2
720
- .map(i => this.of(i))
780
+ .map(i => this.from(i))
721
781
  .reduce((max, item) => (max.$date.valueOf() >= item.$date.valueOf() ? max : item));
722
782
  }
723
783
  }
@@ -810,7 +870,7 @@ function differenceInMonths(a, b) {
810
870
  return -(wholeMonthDiff + ((b.getTime() - anchor) / (anchor2 - anchor)) * sign);
811
871
  }
812
872
  const localTimeFactory = new LocalTimeFactory();
813
- export const localTime = localTimeFactory.of.bind(localTimeFactory);
873
+ export const localTime = localTimeFactory.from.bind(localTimeFactory);
814
874
  // The line below is the blackest of black magic I have ever written in 2024.
815
875
  // And probably 2023 as well.
816
876
  Object.setPrototypeOf(localTime, localTimeFactory);
@@ -11,7 +11,7 @@ export class TimeInterval {
11
11
  this.$end = $end;
12
12
  }
13
13
  static of(start, end) {
14
- return new TimeInterval(localTime.parseToUnixTimestamp(start), localTime.parseToUnixTimestamp(end));
14
+ return new TimeInterval(localTime.from(start).unix, localTime.from(end).unix);
15
15
  }
16
16
  get start() {
17
17
  return this.$start;
@@ -55,7 +55,7 @@ export class TimeInterval {
55
55
  return this.cmp(d) >= 0;
56
56
  }
57
57
  includes(d, incl = '[)') {
58
- d = localTime.parseToUnixTimestamp(d);
58
+ d = localTime.from(d).unix;
59
59
  // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
60
60
  if (d < this.$start || (d === this.$start && incl[0] === '('))
61
61
  return false;
@@ -1,11 +1,11 @@
1
1
  import { localTime } from '../datetime/localTime';
2
2
  export function generateBuildInfoDev() {
3
3
  const now = localTime.now();
4
- const ts = now.unix();
4
+ const ts = now.unix;
5
5
  const rev = 'devRev';
6
6
  const branchName = 'devBranch';
7
7
  const repoName = 'devRepo';
8
- const tsCommit = now.unix();
8
+ const tsCommit = now.unix;
9
9
  const ver = [now.toStringCompact(), repoName, branchName, rev].join('_');
10
10
  return {
11
11
  ts,
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.243.0",
3
+ "version": "14.244.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
7
7
  "test-tz1": "TZ=Europe/Stockholm yarn test local",
8
8
  "test-tz2": "TZ=JST-9 yarn test local",
9
+ "test-ny": "TZ=GMT-0500 yarn test localTime",
9
10
  "docs-dev": "vitepress dev docs --open",
10
11
  "docs-build": "vitepress build docs",
11
12
  "docs-preview": "vitepress preview docs"
@@ -77,7 +77,7 @@ export class DateInterval {
77
77
  */
78
78
  cmp(d: DateIntervalConfig): -1 | 0 | 1 {
79
79
  d = DateInterval.parse(d)
80
- return this.start.cmp(d.start) || this.end.cmp(d.end)
80
+ return this.start.compare(d.start) || this.end.compare(d.end)
81
81
  }
82
82
 
83
83
  getDays(incl: Inclusiveness = '[]'): LocalDate[] {