@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.
Files changed (42) hide show
  1. package/dist/datetime/dateInterval.d.ts +1 -1
  2. package/dist/datetime/dateInterval.js +1 -1
  3. package/dist/datetime/localDate.d.ts +75 -51
  4. package/dist/datetime/localDate.js +256 -200
  5. package/dist/datetime/localTime.d.ts +88 -56
  6. package/dist/datetime/localTime.js +277 -176
  7. package/dist/datetime/timeInterval.d.ts +2 -2
  8. package/dist/datetime/timeInterval.js +2 -2
  9. package/dist/env/buildInfo.js +2 -2
  10. package/dist/error/error.util.d.ts +1 -1
  11. package/dist/index.d.ts +37 -37
  12. package/dist/index.js +37 -37
  13. package/dist/json-schema/from-data/generateJsonSchemaFromData.d.ts +1 -1
  14. package/dist/json-schema/jsonSchemaBuilder.d.ts +1 -1
  15. package/dist/object/object.util.d.ts +1 -1
  16. package/dist/time/time.util.js +4 -2
  17. package/dist/zod/zod.util.d.ts +1 -1
  18. package/dist-esm/datetime/dateInterval.js +1 -1
  19. package/dist-esm/datetime/localDate.js +256 -199
  20. package/dist-esm/datetime/localTime.js +277 -175
  21. package/dist-esm/datetime/timeInterval.js +2 -2
  22. package/dist-esm/decorators/logMethod.decorator.js +1 -1
  23. package/dist-esm/env/buildInfo.js +2 -2
  24. package/dist-esm/index.js +37 -37
  25. package/dist-esm/json-schema/jsonSchemaBuilder.js +1 -1
  26. package/dist-esm/time/time.util.js +4 -2
  27. package/package.json +1 -1
  28. package/src/datetime/dateInterval.ts +2 -2
  29. package/src/datetime/localDate.ts +259 -215
  30. package/src/datetime/localTime.ts +277 -209
  31. package/src/datetime/timeInterval.ts +4 -4
  32. package/src/decorators/logMethod.decorator.ts +1 -1
  33. package/src/define.ts +1 -1
  34. package/src/env/buildInfo.ts +2 -2
  35. package/src/error/error.util.ts +3 -3
  36. package/src/http/fetcher.ts +1 -1
  37. package/src/index.ts +37 -37
  38. package/src/json-schema/from-data/generateJsonSchemaFromData.ts +1 -1
  39. package/src/json-schema/jsonSchemaBuilder.ts +2 -2
  40. package/src/object/object.util.ts +1 -1
  41. package/src/time/time.util.ts +4 -1
  42. package/src/zod/zod.util.ts +1 -1
@@ -1,75 +1,82 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.localDate = exports.LocalDate = void 0;
4
- exports.todayString = todayString;
5
4
  const assert_1 = require("../error/assert");
6
5
  const is_util_1 = require("../is.util");
7
6
  const iterable2_1 = require("../iter/iterable2");
8
7
  const localTime_1 = require("./localTime");
9
8
  const MDAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
10
- const DATE_REGEX = /^(\d\d\d\d)-(\d\d)-(\d\d)/;
9
+ /**
10
+ * Regex is open-ended (no $ at the end) to support e.g Date+Time string to be parsed (time part will be dropped)
11
+ */
12
+ const DATE_REGEX_LOOSE = /^(\d\d\d\d)-(\d\d)-(\d\d)/;
13
+ /**
14
+ * Strict version.
15
+ */
16
+ const DATE_REGEX_STRICT = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
17
+ const COMPACT_DATE_REGEX = /^(\d\d\d\d)(\d\d)(\d\d)$/;
11
18
  /**
12
19
  * LocalDate represents a date without time.
13
20
  * It is timezone-independent.
14
21
  */
15
22
  class LocalDate {
16
- constructor($year, $month, $day) {
17
- this.$year = $year;
18
- this.$month = $month;
19
- this.$day = $day;
23
+ constructor(year, month, day) {
24
+ this.year = year;
25
+ this.month = month;
26
+ this.day = day;
20
27
  }
21
28
  get(unit) {
22
- return unit === 'year' ? this.$year : unit === 'month' ? this.$month : this.$day;
29
+ return unit === 'year' ? this.year : unit === 'month' ? this.month : this.day;
23
30
  }
24
31
  set(unit, v, mutate = false) {
25
32
  const t = mutate ? this : this.clone();
26
33
  if (unit === 'year') {
27
- t.$year = v;
34
+ t.year = v;
28
35
  }
29
36
  else if (unit === 'month') {
30
- t.$month = v;
37
+ t.month = v;
31
38
  }
32
39
  else {
33
- t.$day = v;
40
+ t.day = v;
34
41
  }
35
42
  return t;
36
43
  }
37
- year(v) {
38
- return v === undefined ? this.$year : this.set('year', v);
44
+ setYear(v) {
45
+ return this.set('year', v);
39
46
  }
40
- month(v) {
41
- return v === undefined ? this.$month : this.set('month', v);
47
+ setMonth(v) {
48
+ return this.set('month', v);
42
49
  }
43
- day(v) {
44
- return v === undefined ? this.$day : this.set('day', v);
50
+ setDay(v) {
51
+ return this.set('day', v);
45
52
  }
46
- dayOfWeek() {
53
+ get dayOfWeek() {
47
54
  return (this.toDate().getDay() || 7);
48
55
  }
49
56
  isSame(d) {
50
- d = exports.localDate.of(d);
51
- return this.$day === d.$day && this.$month === d.$month && this.$year === d.$year;
57
+ d = exports.localDate.fromInput(d);
58
+ return this.day === d.day && this.month === d.month && this.year === d.year;
52
59
  }
53
60
  isBefore(d, inclusive = false) {
54
- const r = this.cmp(d);
61
+ const r = this.compare(d);
55
62
  return r === -1 || (r === 0 && inclusive);
56
63
  }
57
64
  isSameOrBefore(d) {
58
- return this.cmp(d) <= 0;
65
+ return this.compare(d) <= 0;
59
66
  }
60
67
  isAfter(d, inclusive = false) {
61
- const r = this.cmp(d);
68
+ const r = this.compare(d);
62
69
  return r === 1 || (r === 0 && inclusive);
63
70
  }
64
71
  isSameOrAfter(d) {
65
- return this.cmp(d) >= 0;
72
+ return this.compare(d) >= 0;
66
73
  }
67
74
  isBetween(min, max, incl = '[)') {
68
- let r = this.cmp(min);
75
+ let r = this.compare(min);
69
76
  // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
70
77
  if (r < 0 || (r === 0 && incl[0] === '('))
71
78
  return false;
72
- r = this.cmp(max);
79
+ r = this.compare(max);
73
80
  if (r > 0 || (r === 0 && incl[1] === ')'))
74
81
  return false;
75
82
  return true;
@@ -84,13 +91,13 @@ class LocalDate {
84
91
  * Third argument allows to override "today".
85
92
  */
86
93
  isOlderThan(n, unit, today) {
87
- return this.isBefore(exports.localDate.of(today || new Date()).plus(-n, unit));
94
+ return this.isBefore(exports.localDate.fromInput(today || new Date()).plus(-n, unit));
88
95
  }
89
96
  /**
90
97
  * Checks if this localDate is same or older (<=) than "today" by X units.
91
98
  */
92
99
  isSameOrOlderThan(n, unit, today) {
93
- return this.isSameOrBefore(exports.localDate.of(today || new Date()).plus(-n, unit));
100
+ return this.isSameOrBefore(exports.localDate.fromInput(today || new Date()).plus(-n, unit));
94
101
  }
95
102
  /**
96
103
  * Checks if this localDate is younger (>) than "today" by X units.
@@ -102,13 +109,13 @@ class LocalDate {
102
109
  * Third argument allows to override "today".
103
110
  */
104
111
  isYoungerThan(n, unit, today) {
105
- return this.isAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
112
+ return this.isAfter(exports.localDate.fromInput(today || new Date()).plus(-n, unit));
106
113
  }
107
114
  /**
108
115
  * Checks if this localDate is same or younger (>=) than "today" by X units.
109
116
  */
110
117
  isSameOrYoungerThan(n, unit, today) {
111
- return this.isSameOrAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
118
+ return this.isSameOrAfter(exports.localDate.fromInput(today || new Date()).plus(-n, unit));
112
119
  }
113
120
  getAgeInYears(today) {
114
121
  return this.getAgeIn('year', today);
@@ -120,26 +127,26 @@ class LocalDate {
120
127
  return this.getAgeIn('day', today);
121
128
  }
122
129
  getAgeIn(unit, today) {
123
- return exports.localDate.of(today || new Date()).diff(this, unit);
130
+ return exports.localDate.fromInput(today || new Date()).diff(this, unit);
124
131
  }
125
132
  /**
126
133
  * Returns 1 if this > d
127
134
  * returns 0 if they are equal
128
135
  * returns -1 if this < d
129
136
  */
130
- cmp(d) {
131
- d = exports.localDate.of(d);
132
- if (this.$year < d.$year)
137
+ compare(d) {
138
+ d = exports.localDate.fromInput(d);
139
+ if (this.year < d.year)
133
140
  return -1;
134
- if (this.$year > d.$year)
141
+ if (this.year > d.year)
135
142
  return 1;
136
- if (this.$month < d.$month)
143
+ if (this.month < d.month)
137
144
  return -1;
138
- if (this.$month > d.$month)
145
+ if (this.month > d.month)
139
146
  return 1;
140
- if (this.$day < d.$day)
147
+ if (this.day < d.day)
141
148
  return -1;
142
- if (this.$day > d.$day)
149
+ if (this.day > d.day)
143
150
  return 1;
144
151
  return 0;
145
152
  }
@@ -155,48 +162,48 @@ class LocalDate {
155
162
  * a.diff(b) means "a minus b"
156
163
  */
157
164
  diff(d, unit) {
158
- d = exports.localDate.of(d);
159
- const sign = this.cmp(d);
165
+ d = exports.localDate.fromInput(d);
166
+ const sign = this.compare(d);
160
167
  if (!sign)
161
168
  return 0;
162
169
  // Put items in descending order: "big minus small"
163
170
  const [big, small] = sign === 1 ? [this, d] : [d, this];
164
171
  if (unit === 'year') {
165
- let years = big.$year - small.$year;
166
- if (big.$month < small.$month ||
167
- (big.$month === small.$month &&
168
- big.$day < small.$day &&
169
- !(big.$day === exports.localDate.getMonthLength(big.$year, big.$month) &&
170
- small.$day === exports.localDate.getMonthLength(small.$year, small.$month)))) {
172
+ let years = big.year - small.year;
173
+ if (big.month < small.month ||
174
+ (big.month === small.month &&
175
+ big.day < small.day &&
176
+ !(big.day === exports.localDate.getMonthLength(big.year, big.month) &&
177
+ small.day === exports.localDate.getMonthLength(small.year, small.month)))) {
171
178
  years--;
172
179
  }
173
180
  return years * sign || 0;
174
181
  }
175
182
  if (unit === 'month') {
176
- let months = (big.$year - small.$year) * 12 + (big.$month - small.$month);
177
- if (big.$day < small.$day) {
178
- const bigMonthLen = exports.localDate.getMonthLength(big.$year, big.$month);
179
- if (big.$day !== bigMonthLen || small.$day < bigMonthLen) {
183
+ let months = (big.year - small.year) * 12 + (big.month - small.month);
184
+ if (big.day < small.day) {
185
+ const bigMonthLen = exports.localDate.getMonthLength(big.year, big.month);
186
+ if (big.day !== bigMonthLen || small.day < bigMonthLen) {
180
187
  months--;
181
188
  }
182
189
  }
183
190
  return months * sign || 0;
184
191
  }
185
192
  // unit is 'day' or 'week'
186
- let days = big.$day - small.$day;
193
+ let days = big.day - small.day;
187
194
  // If small date is after 1st of March - next year's "leapness" should be used
188
- const offsetYear = small.$month >= 3 ? 1 : 0;
189
- for (let year = small.$year; year < big.$year; year++) {
195
+ const offsetYear = small.month >= 3 ? 1 : 0;
196
+ for (let year = small.year; year < big.year; year++) {
190
197
  days += exports.localDate.getYearLength(year + offsetYear);
191
198
  }
192
- if (small.$month < big.$month) {
193
- for (let month = small.$month; month < big.$month; month++) {
194
- days += exports.localDate.getMonthLength(big.$year, month);
199
+ if (small.month < big.month) {
200
+ for (let month = small.month; month < big.month; month++) {
201
+ days += exports.localDate.getMonthLength(big.year, month);
195
202
  }
196
203
  }
197
- else if (big.$month < small.$month) {
198
- for (let month = big.$month; month < small.$month; month++) {
199
- days -= exports.localDate.getMonthLength(big.$year, month);
204
+ else if (big.month < small.month) {
205
+ for (let month = big.month; month < small.month; month++) {
206
+ days -= exports.localDate.getMonthLength(big.year, month);
200
207
  }
201
208
  }
202
209
  if (unit === 'week') {
@@ -229,68 +236,68 @@ class LocalDate {
229
236
  return this.plus(-num, 'year');
230
237
  }
231
238
  plus(num, unit, mutate = false) {
232
- let { $day, $month, $year } = this;
239
+ let { day, month, year } = this;
233
240
  if (unit === 'week') {
234
241
  num *= 7;
235
242
  unit = 'day';
236
243
  }
237
244
  if (unit === 'day') {
238
- $day += num;
245
+ day += num;
239
246
  }
240
247
  else if (unit === 'month') {
241
- $month += num;
248
+ month += num;
242
249
  }
243
250
  else if (unit === 'year') {
244
- $year += num;
251
+ year += num;
245
252
  }
246
253
  // check month overflow
247
- while ($month > 12) {
248
- $year += 1;
249
- $month -= 12;
254
+ while (month > 12) {
255
+ year += 1;
256
+ month -= 12;
250
257
  }
251
- while ($month < 1) {
252
- $year -= 1;
253
- $month += 12;
258
+ while (month < 1) {
259
+ year -= 1;
260
+ month += 12;
254
261
  }
255
262
  // check day overflow
256
263
  // Applies not only for 'day' unit, but also e.g 2022-05-31 plus 1 month should be 2022-06-30 (not 31!)
257
- if ($day < 1) {
258
- while ($day < 1) {
259
- $month -= 1;
260
- if ($month < 1) {
261
- $year -= 1;
262
- $month += 12;
264
+ if (day < 1) {
265
+ while (day < 1) {
266
+ month -= 1;
267
+ if (month < 1) {
268
+ year -= 1;
269
+ month += 12;
263
270
  }
264
- $day += exports.localDate.getMonthLength($year, $month);
271
+ day += exports.localDate.getMonthLength(year, month);
265
272
  }
266
273
  }
267
274
  else {
268
- let monLen = exports.localDate.getMonthLength($year, $month);
275
+ let monLen = exports.localDate.getMonthLength(year, month);
269
276
  if (unit !== 'day') {
270
- if ($day > monLen) {
277
+ if (day > monLen) {
271
278
  // Case of 2022-05-31 plus 1 month should be 2022-06-30, not 31
272
- $day = monLen;
279
+ day = monLen;
273
280
  }
274
281
  }
275
282
  else {
276
- while ($day > monLen) {
277
- $day -= monLen;
278
- $month += 1;
279
- if ($month > 12) {
280
- $year += 1;
281
- $month -= 12;
283
+ while (day > monLen) {
284
+ day -= monLen;
285
+ month += 1;
286
+ if (month > 12) {
287
+ year += 1;
288
+ month -= 12;
282
289
  }
283
- monLen = exports.localDate.getMonthLength($year, $month);
290
+ monLen = exports.localDate.getMonthLength(year, month);
284
291
  }
285
292
  }
286
293
  }
287
294
  if (mutate) {
288
- this.$year = $year;
289
- this.$month = $month;
290
- this.$day = $day;
295
+ this.year = year;
296
+ this.month = month;
297
+ this.day = day;
291
298
  return this;
292
299
  }
293
- return new LocalDate($year, $month, $day);
300
+ return new LocalDate(year, month, day);
294
301
  }
295
302
  minus(num, unit, mutate = false) {
296
303
  return this.plus(-num, unit, mutate);
@@ -299,27 +306,28 @@ class LocalDate {
299
306
  if (unit === 'day')
300
307
  return this;
301
308
  if (unit === 'month')
302
- return new LocalDate(this.$year, this.$month, 1);
309
+ return new LocalDate(this.year, this.month, 1);
303
310
  // year
304
- return new LocalDate(this.$year, 1, 1);
311
+ return new LocalDate(this.year, 1, 1);
305
312
  }
306
313
  endOf(unit) {
307
314
  if (unit === 'day')
308
315
  return this;
309
- if (unit === 'month')
310
- return new LocalDate(this.$year, this.$month, exports.localDate.getMonthLength(this.$year, this.$month));
316
+ if (unit === 'month') {
317
+ return new LocalDate(this.year, this.month, exports.localDate.getMonthLength(this.year, this.month));
318
+ }
311
319
  // year
312
- return new LocalDate(this.$year, 12, 31);
320
+ return new LocalDate(this.year, 12, 31);
313
321
  }
314
322
  /**
315
323
  * Returns how many days are in the current month.
316
324
  * E.g 31 for January.
317
325
  */
318
- daysInMonth() {
319
- return exports.localDate.getMonthLength(this.$year, this.$month);
326
+ get daysInMonth() {
327
+ return exports.localDate.getMonthLength(this.year, this.month);
320
328
  }
321
329
  clone() {
322
- return new LocalDate(this.$year, this.$month, this.$day);
330
+ return new LocalDate(this.year, this.month, this.day);
323
331
  }
324
332
  /**
325
333
  * Converts LocalDate into instance of Date.
@@ -328,7 +336,7 @@ class LocalDate {
328
336
  * Timezone will match local timezone.
329
337
  */
330
338
  toDate() {
331
- return new Date(this.$year, this.$month - 1, this.$day);
339
+ return new Date(this.year, this.month - 1, this.day);
332
340
  }
333
341
  /**
334
342
  * Converts LocalDate to Date in UTC timezone.
@@ -339,9 +347,9 @@ class LocalDate {
339
347
  }
340
348
  toDateObject() {
341
349
  return {
342
- year: this.$year,
343
- month: this.$month,
344
- day: this.$day,
350
+ year: this.year,
351
+ month: this.month,
352
+ day: this.day,
345
353
  };
346
354
  }
347
355
  /**
@@ -349,16 +357,16 @@ class LocalDate {
349
357
  * LocalTime's Date will be in local timezone.
350
358
  */
351
359
  toLocalTime() {
352
- return localTime_1.localTime.of(this.toDate());
360
+ return localTime_1.localTime.fromDate(this.toDate());
353
361
  }
354
362
  /**
355
363
  * Returns e.g: `1984-06-21`
356
364
  */
357
365
  toISODate() {
358
366
  return [
359
- String(this.$year).padStart(4, '0'),
360
- String(this.$month).padStart(2, '0'),
361
- String(this.$day).padStart(2, '0'),
367
+ String(this.year).padStart(4, '0'),
368
+ String(this.month).padStart(2, '0'),
369
+ String(this.day).padStart(2, '0'),
362
370
  ].join('-');
363
371
  }
364
372
  /**
@@ -383,9 +391,9 @@ class LocalDate {
383
391
  */
384
392
  toStringCompact() {
385
393
  return [
386
- String(this.$year).padStart(4, '0'),
387
- String(this.$month).padStart(2, '0'),
388
- String(this.$day).padStart(2, '0'),
394
+ String(this.year).padStart(4, '0'),
395
+ String(this.month).padStart(2, '0'),
396
+ String(this.day).padStart(2, '0'),
389
397
  ].join('');
390
398
  }
391
399
  /**
@@ -397,13 +405,13 @@ class LocalDate {
397
405
  /**
398
406
  * Returns unix timestamp of 00:00:00 of that date (in UTC, because unix timestamp always reflects UTC).
399
407
  */
400
- unix() {
408
+ get unix() {
401
409
  return Math.floor(this.toDate().valueOf() / 1000);
402
410
  }
403
411
  /**
404
412
  * Same as .unix(), but in milliseconds.
405
413
  */
406
- unixMillis() {
414
+ get unixMillis() {
407
415
  return this.toDate().valueOf();
408
416
  }
409
417
  toJSON() {
@@ -419,10 +427,36 @@ class LocalDate {
419
427
  exports.LocalDate = LocalDate;
420
428
  class LocalDateFactory {
421
429
  /**
422
- * Create LocalDate from year, month and day components.
430
+ * Creates a LocalDate from the input, unless it's falsy - then returns undefined.
431
+ *
432
+ * Similar to `localDate.orToday`, but that will instead return Today on falsy input.
423
433
  */
424
- create(year, month, day) {
425
- return new LocalDate(year, month, day);
434
+ orUndefined(d) {
435
+ return d ? this.fromInput(d) : undefined;
436
+ }
437
+ /**
438
+ * Creates a LocalDate from the input, unless it's falsy - then returns localDate.today.
439
+ */
440
+ orToday(d) {
441
+ return d ? this.fromInput(d) : this.today();
442
+ }
443
+ /**
444
+ * Creates LocalDate that represents `today` (in local timezone).
445
+ */
446
+ today() {
447
+ return this.fromDate(new Date());
448
+ }
449
+ /**
450
+ * Creates LocalDate that represents `today` in UTC.
451
+ */
452
+ todayInUTC() {
453
+ return this.fromDateInUTC(new Date());
454
+ }
455
+ /**
456
+ Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
457
+ */
458
+ todayString() {
459
+ return this.fromDate(new Date()).toISODate();
426
460
  }
427
461
  /**
428
462
  * Create LocalDate from LocalDateInput.
@@ -433,67 +467,112 @@ class LocalDateFactory {
433
467
  *
434
468
  * Will throw if it fails to parse/construct LocalDate.
435
469
  */
436
- of(d) {
437
- const t = this.parseOrNull(d);
438
- (0, assert_1._assert)(t !== null, `Cannot parse "${d}" into LocalDate`, {
439
- input: d,
440
- });
441
- return t;
470
+ fromInput(input) {
471
+ if (input instanceof LocalDate)
472
+ return input;
473
+ if (input instanceof Date) {
474
+ return this.fromDate(input);
475
+ }
476
+ // It means it's a string
477
+ return this.fromIsoDateString(input);
478
+ }
479
+ /**
480
+ * Returns true if input is valid to create LocalDate.
481
+ */
482
+ isValid(input) {
483
+ if (!input)
484
+ return false;
485
+ if (input instanceof LocalDate)
486
+ return true;
487
+ if (input instanceof Date)
488
+ return !isNaN(input.getDate());
489
+ return this.isValidString(input);
490
+ }
491
+ /**
492
+ * Returns true if isoString is a valid iso8601 string like `yyyy-mm-dd`.
493
+ */
494
+ isValidString(isoString) {
495
+ return !!this.parseToLocalDateOrUndefined(DATE_REGEX_STRICT, isoString);
442
496
  }
443
497
  /**
444
- * Tries to construct LocalDate from LocalDateInput, returns null otherwise.
445
- * Does not throw (returns null instead).
498
+ * Tries to convert/parse the input into LocalDate.
499
+ * Uses LOOSE parsing.
500
+ * If invalid - doesn't throw, but returns undefined instead.
446
501
  */
447
- parseOrNull(d) {
448
- if (!d)
449
- return null;
450
- if (d instanceof LocalDate)
451
- return d;
452
- if (d instanceof Date) {
453
- return this.fromDate(d);
502
+ try(input) {
503
+ if (!input)
504
+ return;
505
+ if (input instanceof LocalDate)
506
+ return input;
507
+ if (input instanceof Date) {
508
+ if (isNaN(input.getDate()))
509
+ return;
510
+ return new LocalDate(input.getFullYear(), input.getMonth() + 1, input.getDate());
454
511
  }
455
- const m = typeof d === 'string' && DATE_REGEX.exec(d);
512
+ return this.parseToLocalDateOrUndefined(DATE_REGEX_LOOSE, input);
513
+ }
514
+ /**
515
+ * Performs STRICT parsing.
516
+ * Only allows IsoDateString input, nothing else.
517
+ */
518
+ fromIsoDateString(s) {
519
+ return this.parseToLocalDate(DATE_REGEX_STRICT, s);
520
+ }
521
+ /**
522
+ * Parses "compact iso8601 format", e.g `19840621` into LocalDate.
523
+ * Throws if it fails to do so.
524
+ */
525
+ fromCompactString(s) {
526
+ return this.parseToLocalDate(COMPACT_DATE_REGEX, s);
527
+ }
528
+ /**
529
+ * Performs LOOSE parsing.
530
+ * Tries to coerce imprefect/incorrect string input into IsoDateString.
531
+ * Use with caution.
532
+ * Allows to input IsoDateTimeString, will drop the Time part of it.
533
+ */
534
+ parse(s) {
535
+ return this.parseToLocalDate(DATE_REGEX_LOOSE, String(s));
536
+ }
537
+ /**
538
+ * Throws if it fails to parse the input string via Regex and YMD validation.
539
+ */
540
+ parseToLocalDate(regex, s) {
541
+ const ld = this.parseToLocalDateOrUndefined(regex, s);
542
+ (0, assert_1._assert)(ld, `Cannot parse "${s}" into LocalDate`);
543
+ return ld;
544
+ }
545
+ /**
546
+ * Tries to parse the input string, returns undefined if input is invalid.
547
+ */
548
+ parseToLocalDateOrUndefined(regex, s) {
549
+ if (!s || typeof s !== 'string')
550
+ return;
551
+ const m = regex.exec(s);
456
552
  if (!m)
457
- return null;
553
+ return;
458
554
  const year = Number(m[1]);
459
555
  const month = Number(m[2]);
460
556
  const day = Number(m[3]);
461
- if (!year ||
462
- !month ||
463
- month < 1 ||
464
- month > 12 ||
465
- !day ||
466
- day < 1 ||
467
- day > this.getMonthLength(year, month)) {
468
- return null;
469
- }
557
+ if (!this.isDateObjectValid({ year, month, day }))
558
+ return;
470
559
  return new LocalDate(year, month, day);
471
560
  }
472
561
  /**
473
- * Parses "compact iso8601 format", e.g `19840621` into LocalDate.
474
- * Throws if it fails to do so.
562
+ * Throws on invalid value.
475
563
  */
476
- parseCompact(d) {
477
- const [year, month, day] = [d.slice(0, 4), d.slice(4, 2), d.slice(6, 2)].map(Number);
478
- (0, assert_1._assert)(day && month && year, `Cannot parse "${d}" into LocalDate`);
479
- return new LocalDate(year, month, day);
480
- }
481
- getYearLength(year) {
482
- return this.isLeapYear(year) ? 366 : 365;
483
- }
484
- getMonthLength(year, month) {
485
- if (month === 2)
486
- return this.isLeapYear(year) ? 29 : 28;
487
- return MDAYS[month];
564
+ validateDateObject(o) {
565
+ (0, assert_1._assert)(this.isDateObjectValid(o), `Cannot construct LocalDate from: ${o.year}-${o.month}-${o.day}`);
488
566
  }
489
- isLeapYear(year) {
490
- return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
567
+ isDateObjectValid({ year, month, day }) {
568
+ return (!!year && month >= 1 && month <= 12 && day >= 1 && day <= this.getMonthLength(year, month));
491
569
  }
492
570
  /**
493
571
  * Constructs LocalDate from Date.
494
572
  * Takes Date as-is, in its timezone - local or UTC.
495
573
  */
496
574
  fromDate(d) {
575
+ (0, assert_1._assert)(!isNaN(d.getDate()), `localDate.fromDate is called on Date object that is invalid`);
497
576
  return new LocalDate(d.getFullYear(), d.getMonth() + 1, d.getDate());
498
577
  }
499
578
  /**
@@ -501,32 +580,19 @@ class LocalDateFactory {
501
580
  * Takes Date's year/month/day components in UTC, using getUTCFullYear, getUTCMonth, getUTCDate.
502
581
  */
503
582
  fromDateInUTC(d) {
583
+ (0, assert_1._assert)(!isNaN(d.getDate()), `localDate.fromDateInUTC is called on Date object that is invalid`);
504
584
  return new LocalDate(d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate());
505
585
  }
506
- /**
507
- * Returns true if isoString is a valid iso8601 string like `yyyy-mm-dd`.
508
- */
509
- isValid(isoString) {
510
- return this.parseOrNull(isoString) !== null;
511
- }
512
- /**
513
- * Creates LocalDate that represents `today` (in local timezone).
514
- */
515
- today() {
516
- return this.fromDate(new Date());
517
- }
518
- /**
519
- * Creates LocalDate that represents `today` in UTC.
520
- */
521
- todayInUTC() {
522
- return this.fromDateInUTC(new Date());
586
+ fromDateObject(o) {
587
+ this.validateDateObject(o);
588
+ return new LocalDate(o.year, o.month, o.day);
523
589
  }
524
590
  /**
525
591
  * Sorts an array of LocalDates in `dir` order (ascending by default).
526
592
  */
527
593
  sort(items, dir = 'asc', mutate = false) {
528
594
  const mod = dir === 'desc' ? -1 : 1;
529
- return (mutate ? items : [...items]).sort((a, b) => a.cmp(b) * mod);
595
+ return (mutate ? items : [...items]).sort((a, b) => a.compare(b) * mod);
530
596
  }
531
597
  /**
532
598
  * Returns the earliest (min) LocalDate from the array, or undefined if the array is empty.
@@ -542,7 +608,7 @@ class LocalDateFactory {
542
608
  const items2 = items.filter(is_util_1._isTruthy);
543
609
  (0, assert_1._assert)(items2.length, 'localDate.min called on empty array');
544
610
  return items2
545
- .map(i => this.of(i))
611
+ .map(i => this.fromInput(i))
546
612
  .reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
547
613
  }
548
614
  /**
@@ -558,7 +624,9 @@ class LocalDateFactory {
558
624
  max(items) {
559
625
  const items2 = items.filter(is_util_1._isTruthy);
560
626
  (0, assert_1._assert)(items2.length, 'localDate.max called on empty array');
561
- return items2.map(i => this.of(i)).reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
627
+ return items2
628
+ .map(i => this.fromInput(i))
629
+ .reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
562
630
  }
563
631
  /**
564
632
  * Returns the range (array) of LocalDates between min and max.
@@ -576,8 +644,8 @@ class LocalDateFactory {
576
644
  step *= 7;
577
645
  stepUnit = 'day';
578
646
  }
579
- const $min = this.of(min).startOf(stepUnit);
580
- const $max = this.of(max).startOf(stepUnit);
647
+ const $min = this.fromInput(min).startOf(stepUnit);
648
+ const $max = this.fromInput(max).startOf(stepUnit);
581
649
  let value = $min;
582
650
  // eslint-disable-next-line @typescript-eslint/prefer-string-starts-ends-with
583
651
  if (value.isAfter($min, incl[0] === '[')) {
@@ -598,32 +666,20 @@ class LocalDateFactory {
598
666
  },
599
667
  });
600
668
  }
601
- /**
602
- * Creates a LocalDate from the input, unless it's falsy - then returns undefined.
603
- *
604
- * Similar to `localDate.orToday`, but that will instead return Today on falsy input.
605
- */
606
- orUndefined(d) {
607
- return d ? this.of(d) : undefined;
669
+ getYearLength(year) {
670
+ return this.isLeapYear(year) ? 366 : 365;
608
671
  }
609
- /**
610
- * Creates a LocalDate from the input, unless it's falsy - then returns localDate.today.
611
- */
612
- orToday(d) {
613
- return d ? this.of(d) : this.today();
672
+ getMonthLength(year, month) {
673
+ if (month === 2)
674
+ return this.isLeapYear(year) ? 29 : 28;
675
+ return MDAYS[month];
676
+ }
677
+ isLeapYear(year) {
678
+ return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
614
679
  }
615
680
  }
616
681
  const localDateFactory = new LocalDateFactory();
617
- // export const localDate = Object.assign((d: LocalDateInput) => {
618
- // return localDateFactory.of(d)
619
- // }, localDateFactory) as LocalDateFn
620
- exports.localDate = localDateFactory.of.bind(localDateFactory);
682
+ exports.localDate = localDateFactory.fromInput.bind(localDateFactory);
621
683
  // The line below is the blackest of black magic I have ever written in 2024.
622
684
  // And probably 2023 as well.
623
685
  Object.setPrototypeOf(exports.localDate, localDateFactory);
624
- /**
625
- Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
626
- */
627
- function todayString() {
628
- return exports.localDate.fromDate(new Date()).toISODate();
629
- }