@naturalcycles/js-lib 14.99.1 → 14.99.4

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.
@@ -40,7 +40,7 @@ const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7])
40
40
  * @experimental
41
41
  */
42
42
  export class LocalTime {
43
- private constructor(private $date: Date, public utcMode: boolean) {}
43
+ private constructor(private $date: Date) {}
44
44
 
45
45
  /**
46
46
  * Parses input String into LocalDate.
@@ -56,16 +56,6 @@ export class LocalTime {
56
56
  return t
57
57
  }
58
58
 
59
- utc(): this {
60
- this.utcMode = true
61
- return this
62
- }
63
-
64
- local(): this {
65
- this.utcMode = false
66
- return this
67
- }
68
-
69
59
  /**
70
60
  * Returns null if invalid
71
61
  */
@@ -93,7 +83,7 @@ export class LocalTime {
93
83
  // date.setMinutes(date.getMinutes() + date.getTimezoneOffset())
94
84
  // }
95
85
 
96
- return new LocalTime(date, false)
86
+ return new LocalTime(date)
97
87
  }
98
88
 
99
89
  static parseToDate(d: LocalTimeConfig): Date {
@@ -127,58 +117,58 @@ export class LocalTime {
127
117
  }
128
118
 
129
119
  static now(): LocalTime {
130
- return new LocalTime(new Date(), false)
120
+ return new LocalTime(new Date())
131
121
  }
132
122
 
133
123
  static fromComponents(
134
124
  c: { year: number; month: number } & Partial<LocalTimeComponents>,
135
125
  ): LocalTime {
136
- return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second), false)
126
+ return new LocalTime(
127
+ new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0),
128
+ )
137
129
  }
138
130
 
139
131
  get(unit: LocalTimeUnit): number {
140
132
  if (unit === 'year') {
141
- return this.utcMode ? this.$date.getUTCFullYear() : this.$date.getFullYear()
133
+ return this.$date.getFullYear()
142
134
  }
143
135
  if (unit === 'month') {
144
- return (this.utcMode ? this.$date.getUTCMonth() : this.$date.getMonth()) + 1
136
+ return this.$date.getMonth() + 1
145
137
  }
146
138
  if (unit === 'day') {
147
- return this.utcMode ? this.$date.getUTCDate() : this.$date.getDate()
139
+ return this.$date.getDate()
148
140
  }
149
141
  if (unit === 'hour') {
150
- return this.utcMode ? this.$date.getUTCHours() : this.$date.getHours()
142
+ return this.$date.getHours()
151
143
  }
152
144
  if (unit === 'minute') {
153
- return this.utcMode ? this.$date.getUTCMinutes() : this.$date.getMinutes()
145
+ return this.$date.getMinutes()
154
146
  }
155
147
  if (unit === 'week') {
156
148
  return getWeek(this.$date)
157
149
  }
158
150
  // second
159
- return this.utcMode ? this.$date.getUTCSeconds() : this.$date.getSeconds()
151
+ return this.$date.getSeconds()
160
152
  }
161
153
 
162
154
  set(unit: LocalTimeUnit, v: number, mutate = false): LocalTime {
163
155
  const t = mutate ? this : this.clone()
164
156
 
165
- /* eslint-disable @typescript-eslint/no-unused-expressions */
166
157
  if (unit === 'year') {
167
- this.utcMode ? t.$date.setUTCFullYear(v) : t.$date.setFullYear(v)
158
+ t.$date.setFullYear(v)
168
159
  } else if (unit === 'month') {
169
- this.utcMode ? t.$date.setUTCMonth(v - 1) : t.$date.setMonth(v - 1)
160
+ t.$date.setMonth(v - 1)
170
161
  } else if (unit === 'day') {
171
- this.utcMode ? t.$date.setUTCDate(v) : t.$date.setDate(v)
162
+ t.$date.setDate(v)
172
163
  } else if (unit === 'hour') {
173
- this.utcMode ? t.$date.setUTCHours(v) : t.$date.setHours(v)
164
+ t.$date.setHours(v)
174
165
  } else if (unit === 'minute') {
175
- this.utcMode ? t.$date.setUTCMinutes(v) : t.$date.setMinutes(v)
166
+ t.$date.setMinutes(v)
176
167
  } else if (unit === 'second') {
177
- this.utcMode ? t.$date.setUTCSeconds(v) : t.$date.setSeconds(v)
168
+ t.$date.setSeconds(v)
178
169
  } else if (unit === 'week') {
179
170
  setWeek(t.$date, v, true)
180
171
  }
181
- /* eslint-enable @typescript-eslint/no-unused-expressions */
182
172
 
183
173
  return t
184
174
  }
@@ -239,28 +229,26 @@ export class LocalTime {
239
229
  setComponents(c: Partial<LocalTimeComponents>, mutate = false): LocalTime {
240
230
  const d = mutate ? this.$date : new Date(this.$date)
241
231
 
242
- /* eslint-disable @typescript-eslint/no-unused-expressions */
243
- if (c.year) {
244
- this.utcMode ? d.setUTCFullYear(c.year) : d.setFullYear(c.year)
245
- }
246
- if (c.month) {
247
- this.utcMode ? d.setUTCMonth(c.month - 1) : d.setMonth(c.month - 1)
248
- }
249
- if (c.day) {
250
- this.utcMode ? d.setUTCDate(c.day) : d.setDate(c.day)
232
+ // Year, month and day set all-at-once, to avoid 30/31 (and 28/29) mishap
233
+ if (c.day || c.month !== undefined || c.year !== undefined) {
234
+ d.setFullYear(
235
+ c.year ?? d.getFullYear(),
236
+ c.month ? c.month - 1 : d.getMonth(),
237
+ c.day || d.getDate(),
238
+ )
251
239
  }
240
+
252
241
  if (c.hour !== undefined) {
253
- this.utcMode ? d.setUTCHours(c.hour) : d.setHours(c.hour)
242
+ d.setHours(c.hour)
254
243
  }
255
244
  if (c.minute !== undefined) {
256
- this.utcMode ? d.setUTCMinutes(c.minute) : d.setMinutes(c.minute)
245
+ d.setMinutes(c.minute)
257
246
  }
258
247
  if (c.second !== undefined) {
259
- this.utcMode ? d.setUTCSeconds(c.second) : d.setSeconds(c.second)
248
+ d.setSeconds(c.second)
260
249
  }
261
- /* eslint-enable @typescript-eslint/no-unused-expressions */
262
250
 
263
- return mutate ? this : new LocalTime(d, this.utcMode)
251
+ return mutate ? this : new LocalTime(d)
264
252
  }
265
253
 
266
254
  add(num: number, unit: LocalTimeUnit, mutate = false): LocalTime {
@@ -268,6 +256,12 @@ export class LocalTime {
268
256
  num *= 7
269
257
  unit = 'day'
270
258
  }
259
+
260
+ if (unit === 'year' || unit === 'month') {
261
+ const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate)
262
+ return mutate ? this : LocalTime.of(d)
263
+ }
264
+
271
265
  return this.set(unit, this.get(unit) + num, mutate)
272
266
  }
273
267
 
@@ -285,37 +279,13 @@ export class LocalTime {
285
279
  const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000
286
280
  if (!secDiff) return 0
287
281
 
288
- if (unit === 'year' || unit === 'month') {
289
- const sign = secDiff > 0 ? 1 : -1
290
-
291
- // Put items in descending order: "big minus small"
292
- const [big, small] = sign === 1 ? [this.$date, date2] : [date2, this.$date]
293
-
294
- if (unit === 'year') {
295
- let years = big.getFullYear() - small.getFullYear()
296
- const big2 = new Date(big)
297
- const small2 = new Date(small)
298
- big2.setFullYear(1584)
299
- small2.setFullYear(1584)
300
- if (big2 < small2) years--
301
- return years * sign || 0
302
- }
303
-
304
- if (unit === 'month') {
305
- let months =
306
- (big.getFullYear() - small.getFullYear()) * 12 + big.getMonth() - small.getMonth()
307
- const big2 = new Date(big)
308
- const small2 = new Date(small)
309
- big2.setFullYear(1584, 0)
310
- small2.setFullYear(1584, 0)
311
- if (big2 < small2) months--
312
- return months * sign || 0
313
- }
314
- }
315
-
316
282
  let r
317
283
 
318
- if (unit === 'day') {
284
+ if (unit === 'year') {
285
+ r = differenceInMonths(this.getDate(), date2) / 12
286
+ } else if (unit === 'month') {
287
+ r = differenceInMonths(this.getDate(), date2)
288
+ } else if (unit === 'day') {
319
289
  r = secDiff / SECONDS_IN_DAY
320
290
  } else if (unit === 'week') {
321
291
  r = secDiff / (7 * 24 * 60 * 60)
@@ -337,19 +307,18 @@ export class LocalTime {
337
307
  const d = mutate ? this.$date : new Date(this.$date)
338
308
  d.setSeconds(0, 0)
339
309
 
340
- /* eslint-disable @typescript-eslint/no-unused-expressions */
341
310
  if (unit !== 'minute') {
342
- this.utcMode ? d.setUTCMinutes(0) : d.setMinutes(0)
311
+ d.setMinutes(0)
343
312
  if (unit !== 'hour') {
344
- this.utcMode ? d.setUTCHours(0) : d.setHours(0)
313
+ d.setHours(0)
345
314
  if (unit !== 'day') {
346
315
  // year, month or week
347
316
 
348
317
  if (unit === 'year') {
349
- this.utcMode ? d.setUTCMonth(0) : d.setMonth(0)
350
- this.utcMode ? d.setUTCDate(1) : d.setDate(1)
318
+ d.setMonth(0)
319
+ d.setDate(1)
351
320
  } else if (unit === 'month') {
352
- this.utcMode ? d.setUTCDate(1) : d.setDate(1)
321
+ d.setDate(1)
353
322
  } else {
354
323
  // week
355
324
  startOfWeek(d, true)
@@ -357,9 +326,8 @@ export class LocalTime {
357
326
  }
358
327
  }
359
328
  }
360
- /* eslint-enable @typescript-eslint/no-unused-expressions */
361
329
 
362
- return mutate ? this : new LocalTime(d, this.utcMode)
330
+ return mutate ? this : new LocalTime(d)
363
331
  }
364
332
 
365
333
  endOf(unit: LocalTimeUnit, mutate = false): LocalTime {
@@ -367,16 +335,15 @@ export class LocalTime {
367
335
  const d = mutate ? this.$date : new Date(this.$date)
368
336
  d.setSeconds(59, 0)
369
337
 
370
- /* eslint-disable @typescript-eslint/no-unused-expressions */
371
338
  if (unit !== 'minute') {
372
- this.utcMode ? d.setUTCMinutes(59) : d.setMinutes(59)
339
+ d.setMinutes(59)
373
340
  if (unit !== 'hour') {
374
- this.utcMode ? d.setUTCHours(23) : d.setHours(23)
341
+ d.setHours(23)
375
342
  if (unit !== 'day') {
376
343
  // year, month or week
377
344
 
378
345
  if (unit === 'year') {
379
- this.utcMode ? d.setUTCMonth(11) : d.setMonth(11)
346
+ d.setMonth(11)
380
347
  }
381
348
 
382
349
  if (unit === 'week') {
@@ -384,14 +351,13 @@ export class LocalTime {
384
351
  } else {
385
352
  // year or month
386
353
  const lastDay = LocalDate.getMonthLength(d.getFullYear(), d.getMonth() + 1)
387
- this.utcMode ? d.setUTCDate(lastDay) : d.setDate(lastDay)
354
+ d.setDate(lastDay)
388
355
  }
389
356
  }
390
357
  }
391
358
  }
392
- /* eslint-enable @typescript-eslint/no-unused-expressions */
393
359
 
394
- return mutate ? this : new LocalTime(d, this.utcMode)
360
+ return mutate ? this : new LocalTime(d)
395
361
  }
396
362
 
397
363
  static sort(items: LocalTime[], mutate = false, descending = false): LocalTime[] {
@@ -471,17 +437,6 @@ export class LocalTime {
471
437
  }
472
438
 
473
439
  components(): LocalTimeComponents {
474
- if (this.utcMode) {
475
- return {
476
- year: this.$date.getUTCFullYear(),
477
- month: this.$date.getUTCMonth() + 1,
478
- day: this.$date.getUTCDate(),
479
- hour: this.$date.getUTCHours(),
480
- minute: this.$date.getUTCMinutes(),
481
- second: this.$date.getSeconds(),
482
- }
483
- }
484
-
485
440
  return {
486
441
  year: this.$date.getFullYear(),
487
442
  month: this.$date.getMonth() + 1,
@@ -509,7 +464,7 @@ export class LocalTime {
509
464
  }
510
465
 
511
466
  clone(): LocalTime {
512
- return new LocalTime(new Date(this.$date), this.utcMode)
467
+ return new LocalTime(new Date(this.$date))
513
468
  }
514
469
 
515
470
  unix(): UnixTimestampNumber {
@@ -525,14 +480,6 @@ export class LocalTime {
525
480
  }
526
481
 
527
482
  toLocalDate(): LocalDate {
528
- if (this.utcMode) {
529
- return LocalDate.create(
530
- this.$date.getUTCFullYear(),
531
- this.$date.getUTCMonth() + 1,
532
- this.$date.getUTCDate(),
533
- )
534
- }
535
-
536
483
  return LocalDate.create(
537
484
  this.$date.getFullYear(),
538
485
  this.$date.getMonth() + 1,
@@ -622,7 +569,7 @@ export class LocalTime {
622
569
  }
623
570
 
624
571
  toString(): string {
625
- return String(this.unix())
572
+ return this.toISODateTime()
626
573
  }
627
574
 
628
575
  toJSON(): UnixTimestampNumber {
@@ -686,32 +633,6 @@ function getWeekYear(date: Date): number {
686
633
  }
687
634
  }
688
635
 
689
- // function setWeekYear(
690
- // date: Date,
691
- // year: number,
692
- // ): Date {
693
- // const diff = differenceInCalendarDays(date, startOfWeekYear(date))
694
- // const fourthOfJanuary = new Date(0)
695
- // fourthOfJanuary.setFullYear(year, 0, 4)
696
- // fourthOfJanuary.setHours(0, 0, 0, 0)
697
- // date = startOfWeekYear(fourthOfJanuary)
698
- // date.setDate(date.getDate() + diff)
699
- // return date
700
- // }
701
-
702
- // function differenceInCalendarDays(
703
- // dateLeft: Date,
704
- // dateRight: Date,
705
- // ): number {
706
- // return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
707
- // }
708
-
709
- // function startOfDay(date: Date, mutate = false): Date {
710
- // const d = mutate ? date : new Date(date)
711
- // d.setHours(0, 0, 0, 0)
712
- // return d
713
- // }
714
-
715
636
  // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
716
637
  function startOfWeek(date: Date, mutate = false): Date {
717
638
  const d = mutate ? date : new Date(date)
@@ -734,3 +655,41 @@ function endOfWeek(date: Date, mutate = false): Date {
734
655
  d.setDate(d.getDate() + diff)
735
656
  return d
736
657
  }
658
+
659
+ function addMonths(d: Date, num: number, mutate = false): Date {
660
+ if (!mutate) d = new Date(d)
661
+
662
+ let day = d.getDate()
663
+ let month = d.getMonth() + 1 + num
664
+
665
+ if (day < 29) {
666
+ d.setMonth(month - 1)
667
+ return d
668
+ }
669
+
670
+ let year = d.getFullYear()
671
+
672
+ while (month > 12) {
673
+ year++
674
+ month -= 12
675
+ }
676
+ while (month < 1) {
677
+ year--
678
+ month += 12
679
+ }
680
+
681
+ const monthLen = LocalDate.getMonthLength(year, month)
682
+ if (day > monthLen) day = monthLen
683
+
684
+ d.setFullYear(year, month - 1, day)
685
+ return d
686
+ }
687
+
688
+ function differenceInMonths(a: Date, b: Date): number {
689
+ if (a.getDate() < b.getDate()) return -differenceInMonths(b, a)
690
+ const wholeMonthDiff = (b.getFullYear() - a.getFullYear()) * 12 + (b.getMonth() - a.getMonth())
691
+ const anchor = addMonths(a, wholeMonthDiff).getTime()
692
+ const sign = b.getTime() - anchor >= 0 ? 1 : -1
693
+ const anchor2 = addMonths(a, wholeMonthDiff + sign).getTime()
694
+ return -(wholeMonthDiff + ((b.getTime() - anchor) / (anchor2 - anchor)) * sign)
695
+ }