@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.
@@ -218,15 +218,23 @@ class LocalDate {
218
218
  const [big, small] = sign === 1 ? [this, d] : [d, this];
219
219
  if (unit === 'year') {
220
220
  let years = big.$year - small.$year;
221
- if (big.$month < small.$month || (big.$month === small.$month && big.$day < small.$day)) {
221
+ if (big.$month < small.$month ||
222
+ (big.$month === small.$month &&
223
+ big.$day < small.$day &&
224
+ !(big.$day === LocalDate.getMonthLength(big.$year, big.$month) &&
225
+ small.$day === LocalDate.getMonthLength(small.$year, small.$month)))) {
222
226
  years--;
223
227
  }
224
228
  return years * sign || 0;
225
229
  }
226
230
  if (unit === 'month') {
227
231
  let months = (big.$year - small.$year) * 12 + (big.$month - small.$month);
228
- if (big.$day < small.$day)
229
- months--;
232
+ if (big.$day < small.$day) {
233
+ const bigMonthLen = LocalDate.getMonthLength(big.$year, big.$month);
234
+ if (big.$day !== bigMonthLen || small.$day < bigMonthLen) {
235
+ months--;
236
+ }
237
+ }
230
238
  return months * sign || 0;
231
239
  }
232
240
  // unit is 'day' or 'week'
@@ -266,20 +274,36 @@ class LocalDate {
266
274
  else if (unit === 'year') {
267
275
  $year += num;
268
276
  }
277
+ // check month overflow
278
+ while ($month > 12) {
279
+ $year += 1;
280
+ $month -= 12;
281
+ }
282
+ while ($month < 1) {
283
+ $year -= 1;
284
+ $month += 12;
285
+ }
269
286
  // check day overflow
270
- if (unit === 'day') {
271
- if ($day < 1) {
272
- while ($day < 1) {
273
- $month -= 1;
274
- if ($month < 1) {
275
- $year -= 1;
276
- $month += 12;
277
- }
278
- $day += LocalDate.getMonthLength($year, $month);
287
+ // Applies not only for 'day' unit, but also e.g 2022-05-31 plus 1 month should be 2022-06-30 (not 31!)
288
+ if ($day < 1) {
289
+ while ($day < 1) {
290
+ $month -= 1;
291
+ if ($month < 1) {
292
+ $year -= 1;
293
+ $month += 12;
294
+ }
295
+ $day += LocalDate.getMonthLength($year, $month);
296
+ }
297
+ }
298
+ else {
299
+ let monLen = LocalDate.getMonthLength($year, $month);
300
+ if (unit !== 'day') {
301
+ if ($day > monLen) {
302
+ // Case of 2022-05-31 plus 1 month should be 2022-06-30, not 31
303
+ $day = monLen;
279
304
  }
280
305
  }
281
306
  else {
282
- let monLen = LocalDate.getMonthLength($year, $month);
283
307
  while ($day > monLen) {
284
308
  $day -= monLen;
285
309
  $month += 1;
@@ -291,15 +315,6 @@ class LocalDate {
291
315
  }
292
316
  }
293
317
  }
294
- // check month overflow
295
- while ($month > 12) {
296
- $year += 1;
297
- $month -= 12;
298
- }
299
- while ($month < 1) {
300
- $year -= 1;
301
- $month += 12;
302
- }
303
318
  if (mutate) {
304
319
  this.$year = $year;
305
320
  this.$month = $month;
@@ -25,15 +25,12 @@ export interface LocalTimeComponents {
25
25
  */
26
26
  export declare class LocalTime {
27
27
  private $date;
28
- utcMode: boolean;
29
28
  private constructor();
30
29
  /**
31
30
  * Parses input String into LocalDate.
32
31
  * Input can already be a LocalDate - it is returned as-is in that case.
33
32
  */
34
33
  static of(d: LocalTimeConfig): LocalTime;
35
- utc(): this;
36
- local(): this;
37
34
  /**
38
35
  * Returns null if invalid
39
36
  */
@@ -25,9 +25,8 @@ const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
25
25
  * @experimental
26
26
  */
27
27
  class LocalTime {
28
- constructor($date, utcMode) {
28
+ constructor($date) {
29
29
  this.$date = $date;
30
- this.utcMode = utcMode;
31
30
  }
32
31
  /**
33
32
  * Parses input String into LocalDate.
@@ -40,14 +39,6 @@ class LocalTime {
40
39
  }
41
40
  return t;
42
41
  }
43
- utc() {
44
- this.utcMode = true;
45
- return this;
46
- }
47
- local() {
48
- this.utcMode = false;
49
- return this;
50
- }
51
42
  /**
52
43
  * Returns null if invalid
53
44
  */
@@ -74,7 +65,7 @@ class LocalTime {
74
65
  // if (utc) {
75
66
  // date.setMinutes(date.getMinutes() + date.getTimezoneOffset())
76
67
  // }
77
- return new LocalTime(date, false);
68
+ return new LocalTime(date);
78
69
  }
79
70
  static parseToDate(d) {
80
71
  if (d instanceof LocalTime)
@@ -102,58 +93,56 @@ class LocalTime {
102
93
  return this.parseOrNull(d) !== null;
103
94
  }
104
95
  static now() {
105
- return new LocalTime(new Date(), false);
96
+ return new LocalTime(new Date());
106
97
  }
107
98
  static fromComponents(c) {
108
- return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second), false);
99
+ return new LocalTime(new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0));
109
100
  }
110
101
  get(unit) {
111
102
  if (unit === 'year') {
112
- return this.utcMode ? this.$date.getUTCFullYear() : this.$date.getFullYear();
103
+ return this.$date.getFullYear();
113
104
  }
114
105
  if (unit === 'month') {
115
- return (this.utcMode ? this.$date.getUTCMonth() : this.$date.getMonth()) + 1;
106
+ return this.$date.getMonth() + 1;
116
107
  }
117
108
  if (unit === 'day') {
118
- return this.utcMode ? this.$date.getUTCDate() : this.$date.getDate();
109
+ return this.$date.getDate();
119
110
  }
120
111
  if (unit === 'hour') {
121
- return this.utcMode ? this.$date.getUTCHours() : this.$date.getHours();
112
+ return this.$date.getHours();
122
113
  }
123
114
  if (unit === 'minute') {
124
- return this.utcMode ? this.$date.getUTCMinutes() : this.$date.getMinutes();
115
+ return this.$date.getMinutes();
125
116
  }
126
117
  if (unit === 'week') {
127
118
  return getWeek(this.$date);
128
119
  }
129
120
  // second
130
- return this.utcMode ? this.$date.getUTCSeconds() : this.$date.getSeconds();
121
+ return this.$date.getSeconds();
131
122
  }
132
123
  set(unit, v, mutate = false) {
133
124
  const t = mutate ? this : this.clone();
134
- /* eslint-disable @typescript-eslint/no-unused-expressions */
135
125
  if (unit === 'year') {
136
- this.utcMode ? t.$date.setUTCFullYear(v) : t.$date.setFullYear(v);
126
+ t.$date.setFullYear(v);
137
127
  }
138
128
  else if (unit === 'month') {
139
- this.utcMode ? t.$date.setUTCMonth(v - 1) : t.$date.setMonth(v - 1);
129
+ t.$date.setMonth(v - 1);
140
130
  }
141
131
  else if (unit === 'day') {
142
- this.utcMode ? t.$date.setUTCDate(v) : t.$date.setDate(v);
132
+ t.$date.setDate(v);
143
133
  }
144
134
  else if (unit === 'hour') {
145
- this.utcMode ? t.$date.setUTCHours(v) : t.$date.setHours(v);
135
+ t.$date.setHours(v);
146
136
  }
147
137
  else if (unit === 'minute') {
148
- this.utcMode ? t.$date.setUTCMinutes(v) : t.$date.setMinutes(v);
138
+ t.$date.setMinutes(v);
149
139
  }
150
140
  else if (unit === 'second') {
151
- this.utcMode ? t.$date.setUTCSeconds(v) : t.$date.setSeconds(v);
141
+ t.$date.setSeconds(v);
152
142
  }
153
143
  else if (unit === 'week') {
154
144
  setWeek(t.$date, v, true);
155
145
  }
156
- /* eslint-enable @typescript-eslint/no-unused-expressions */
157
146
  return t;
158
147
  }
159
148
  year(v) {
@@ -188,33 +177,30 @@ class LocalTime {
188
177
  }
189
178
  setComponents(c, mutate = false) {
190
179
  const d = mutate ? this.$date : new Date(this.$date);
191
- /* eslint-disable @typescript-eslint/no-unused-expressions */
192
- if (c.year) {
193
- this.utcMode ? d.setUTCFullYear(c.year) : d.setFullYear(c.year);
194
- }
195
- if (c.month) {
196
- this.utcMode ? d.setUTCMonth(c.month - 1) : d.setMonth(c.month - 1);
197
- }
198
- if (c.day) {
199
- this.utcMode ? d.setUTCDate(c.day) : d.setDate(c.day);
180
+ // Year, month and day set all-at-once, to avoid 30/31 (and 28/29) mishap
181
+ if (c.day || c.month !== undefined || c.year !== undefined) {
182
+ d.setFullYear(c.year ?? d.getFullYear(), c.month ? c.month - 1 : d.getMonth(), c.day || d.getDate());
200
183
  }
201
184
  if (c.hour !== undefined) {
202
- this.utcMode ? d.setUTCHours(c.hour) : d.setHours(c.hour);
185
+ d.setHours(c.hour);
203
186
  }
204
187
  if (c.minute !== undefined) {
205
- this.utcMode ? d.setUTCMinutes(c.minute) : d.setMinutes(c.minute);
188
+ d.setMinutes(c.minute);
206
189
  }
207
190
  if (c.second !== undefined) {
208
- this.utcMode ? d.setUTCSeconds(c.second) : d.setSeconds(c.second);
191
+ d.setSeconds(c.second);
209
192
  }
210
- /* eslint-enable @typescript-eslint/no-unused-expressions */
211
- return mutate ? this : new LocalTime(d, this.utcMode);
193
+ return mutate ? this : new LocalTime(d);
212
194
  }
213
195
  add(num, unit, mutate = false) {
214
196
  if (unit === 'week') {
215
197
  num *= 7;
216
198
  unit = 'day';
217
199
  }
200
+ if (unit === 'year' || unit === 'month') {
201
+ const d = addMonths(this.$date, unit === 'month' ? num : num * 12, mutate);
202
+ return mutate ? this : LocalTime.of(d);
203
+ }
218
204
  return this.set(unit, this.get(unit) + num, mutate);
219
205
  }
220
206
  subtract(num, unit, mutate = false) {
@@ -228,33 +214,14 @@ class LocalTime {
228
214
  const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
229
215
  if (!secDiff)
230
216
  return 0;
231
- if (unit === 'year' || unit === 'month') {
232
- const sign = secDiff > 0 ? 1 : -1;
233
- // Put items in descending order: "big minus small"
234
- const [big, small] = sign === 1 ? [this.$date, date2] : [date2, this.$date];
235
- if (unit === 'year') {
236
- let years = big.getFullYear() - small.getFullYear();
237
- const big2 = new Date(big);
238
- const small2 = new Date(small);
239
- big2.setFullYear(1584);
240
- small2.setFullYear(1584);
241
- if (big2 < small2)
242
- years--;
243
- return years * sign || 0;
244
- }
245
- if (unit === 'month') {
246
- let months = (big.getFullYear() - small.getFullYear()) * 12 + big.getMonth() - small.getMonth();
247
- const big2 = new Date(big);
248
- const small2 = new Date(small);
249
- big2.setFullYear(1584, 0);
250
- small2.setFullYear(1584, 0);
251
- if (big2 < small2)
252
- months--;
253
- return months * sign || 0;
254
- }
255
- }
256
217
  let r;
257
- if (unit === 'day') {
218
+ if (unit === 'year') {
219
+ r = differenceInMonths(this.getDate(), date2) / 12;
220
+ }
221
+ else if (unit === 'month') {
222
+ r = differenceInMonths(this.getDate(), date2);
223
+ }
224
+ else if (unit === 'day') {
258
225
  r = secDiff / SECONDS_IN_DAY;
259
226
  }
260
227
  else if (unit === 'week') {
@@ -278,19 +245,18 @@ class LocalTime {
278
245
  return this;
279
246
  const d = mutate ? this.$date : new Date(this.$date);
280
247
  d.setSeconds(0, 0);
281
- /* eslint-disable @typescript-eslint/no-unused-expressions */
282
248
  if (unit !== 'minute') {
283
- this.utcMode ? d.setUTCMinutes(0) : d.setMinutes(0);
249
+ d.setMinutes(0);
284
250
  if (unit !== 'hour') {
285
- this.utcMode ? d.setUTCHours(0) : d.setHours(0);
251
+ d.setHours(0);
286
252
  if (unit !== 'day') {
287
253
  // year, month or week
288
254
  if (unit === 'year') {
289
- this.utcMode ? d.setUTCMonth(0) : d.setMonth(0);
290
- this.utcMode ? d.setUTCDate(1) : d.setDate(1);
255
+ d.setMonth(0);
256
+ d.setDate(1);
291
257
  }
292
258
  else if (unit === 'month') {
293
- this.utcMode ? d.setUTCDate(1) : d.setDate(1);
259
+ d.setDate(1);
294
260
  }
295
261
  else {
296
262
  // week
@@ -299,23 +265,21 @@ class LocalTime {
299
265
  }
300
266
  }
301
267
  }
302
- /* eslint-enable @typescript-eslint/no-unused-expressions */
303
- return mutate ? this : new LocalTime(d, this.utcMode);
268
+ return mutate ? this : new LocalTime(d);
304
269
  }
305
270
  endOf(unit, mutate = false) {
306
271
  if (unit === 'second')
307
272
  return this;
308
273
  const d = mutate ? this.$date : new Date(this.$date);
309
274
  d.setSeconds(59, 0);
310
- /* eslint-disable @typescript-eslint/no-unused-expressions */
311
275
  if (unit !== 'minute') {
312
- this.utcMode ? d.setUTCMinutes(59) : d.setMinutes(59);
276
+ d.setMinutes(59);
313
277
  if (unit !== 'hour') {
314
- this.utcMode ? d.setUTCHours(23) : d.setHours(23);
278
+ d.setHours(23);
315
279
  if (unit !== 'day') {
316
280
  // year, month or week
317
281
  if (unit === 'year') {
318
- this.utcMode ? d.setUTCMonth(11) : d.setMonth(11);
282
+ d.setMonth(11);
319
283
  }
320
284
  if (unit === 'week') {
321
285
  endOfWeek(d, true);
@@ -323,13 +287,12 @@ class LocalTime {
323
287
  else {
324
288
  // year or month
325
289
  const lastDay = localDate_1.LocalDate.getMonthLength(d.getFullYear(), d.getMonth() + 1);
326
- this.utcMode ? d.setUTCDate(lastDay) : d.setDate(lastDay);
290
+ d.setDate(lastDay);
327
291
  }
328
292
  }
329
293
  }
330
294
  }
331
- /* eslint-enable @typescript-eslint/no-unused-expressions */
332
- return mutate ? this : new LocalTime(d, this.utcMode);
295
+ return mutate ? this : new LocalTime(d);
333
296
  }
334
297
  static sort(items, mutate = false, descending = false) {
335
298
  const mod = descending ? -1 : 1;
@@ -398,16 +361,6 @@ class LocalTime {
398
361
  return t1 < t2 ? -1 : 1;
399
362
  }
400
363
  components() {
401
- if (this.utcMode) {
402
- return {
403
- year: this.$date.getUTCFullYear(),
404
- month: this.$date.getUTCMonth() + 1,
405
- day: this.$date.getUTCDate(),
406
- hour: this.$date.getUTCHours(),
407
- minute: this.$date.getUTCMinutes(),
408
- second: this.$date.getSeconds(),
409
- };
410
- }
411
364
  return {
412
365
  year: this.$date.getFullYear(),
413
366
  month: this.$date.getMonth() + 1,
@@ -430,7 +383,7 @@ class LocalTime {
430
383
  return this.$date;
431
384
  }
432
385
  clone() {
433
- return new LocalTime(new Date(this.$date), this.utcMode);
386
+ return new LocalTime(new Date(this.$date));
434
387
  }
435
388
  unix() {
436
389
  return Math.floor(this.$date.valueOf() / 1000);
@@ -442,9 +395,6 @@ class LocalTime {
442
395
  return Math.floor(this.$date.valueOf() / 1000);
443
396
  }
444
397
  toLocalDate() {
445
- if (this.utcMode) {
446
- return localDate_1.LocalDate.create(this.$date.getUTCFullYear(), this.$date.getUTCMonth() + 1, this.$date.getUTCDate());
447
- }
448
398
  return localDate_1.LocalDate.create(this.$date.getFullYear(), this.$date.getMonth() + 1, this.$date.getDate());
449
399
  }
450
400
  toPretty(seconds = true) {
@@ -516,7 +466,7 @@ class LocalTime {
516
466
  ].join('');
517
467
  }
518
468
  toString() {
519
- return String(this.unix());
469
+ return this.toISODateTime();
520
470
  }
521
471
  toJSON() {
522
472
  return this.unix();
@@ -573,29 +523,6 @@ function getWeekYear(date) {
573
523
  return year - 1;
574
524
  }
575
525
  }
576
- // function setWeekYear(
577
- // date: Date,
578
- // year: number,
579
- // ): Date {
580
- // const diff = differenceInCalendarDays(date, startOfWeekYear(date))
581
- // const fourthOfJanuary = new Date(0)
582
- // fourthOfJanuary.setFullYear(year, 0, 4)
583
- // fourthOfJanuary.setHours(0, 0, 0, 0)
584
- // date = startOfWeekYear(fourthOfJanuary)
585
- // date.setDate(date.getDate() + diff)
586
- // return date
587
- // }
588
- // function differenceInCalendarDays(
589
- // dateLeft: Date,
590
- // dateRight: Date,
591
- // ): number {
592
- // return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
593
- // }
594
- // function startOfDay(date: Date, mutate = false): Date {
595
- // const d = mutate ? date : new Date(date)
596
- // d.setHours(0, 0, 0, 0)
597
- // return d
598
- // }
599
526
  // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
600
527
  function startOfWeek(date, mutate = false) {
601
528
  const d = mutate ? date : new Date(date);
@@ -613,3 +540,36 @@ function endOfWeek(date, mutate = false) {
613
540
  d.setDate(d.getDate() + diff);
614
541
  return d;
615
542
  }
543
+ function addMonths(d, num, mutate = false) {
544
+ if (!mutate)
545
+ d = new Date(d);
546
+ let day = d.getDate();
547
+ let month = d.getMonth() + 1 + num;
548
+ if (day < 29) {
549
+ d.setMonth(month - 1);
550
+ return d;
551
+ }
552
+ let year = d.getFullYear();
553
+ while (month > 12) {
554
+ year++;
555
+ month -= 12;
556
+ }
557
+ while (month < 1) {
558
+ year--;
559
+ month += 12;
560
+ }
561
+ const monthLen = localDate_1.LocalDate.getMonthLength(year, month);
562
+ if (day > monthLen)
563
+ day = monthLen;
564
+ d.setFullYear(year, month - 1, day);
565
+ return d;
566
+ }
567
+ function differenceInMonths(a, b) {
568
+ if (a.getDate() < b.getDate())
569
+ return -differenceInMonths(b, a);
570
+ const wholeMonthDiff = (b.getFullYear() - a.getFullYear()) * 12 + (b.getMonth() - a.getMonth());
571
+ const anchor = addMonths(a, wholeMonthDiff).getTime();
572
+ const sign = b.getTime() - anchor >= 0 ? 1 : -1;
573
+ const anchor2 = addMonths(a, wholeMonthDiff + sign).getTime();
574
+ return -(wholeMonthDiff + ((b.getTime() - anchor) / (anchor2 - anchor)) * sign);
575
+ }
@@ -215,15 +215,23 @@ export class LocalDate {
215
215
  const [big, small] = sign === 1 ? [this, d] : [d, this];
216
216
  if (unit === 'year') {
217
217
  let years = big.$year - small.$year;
218
- if (big.$month < small.$month || (big.$month === small.$month && big.$day < small.$day)) {
218
+ if (big.$month < small.$month ||
219
+ (big.$month === small.$month &&
220
+ big.$day < small.$day &&
221
+ !(big.$day === LocalDate.getMonthLength(big.$year, big.$month) &&
222
+ small.$day === LocalDate.getMonthLength(small.$year, small.$month)))) {
219
223
  years--;
220
224
  }
221
225
  return years * sign || 0;
222
226
  }
223
227
  if (unit === 'month') {
224
228
  let months = (big.$year - small.$year) * 12 + (big.$month - small.$month);
225
- if (big.$day < small.$day)
226
- months--;
229
+ if (big.$day < small.$day) {
230
+ const bigMonthLen = LocalDate.getMonthLength(big.$year, big.$month);
231
+ if (big.$day !== bigMonthLen || small.$day < bigMonthLen) {
232
+ months--;
233
+ }
234
+ }
227
235
  return months * sign || 0;
228
236
  }
229
237
  // unit is 'day' or 'week'
@@ -263,20 +271,36 @@ export class LocalDate {
263
271
  else if (unit === 'year') {
264
272
  $year += num;
265
273
  }
274
+ // check month overflow
275
+ while ($month > 12) {
276
+ $year += 1;
277
+ $month -= 12;
278
+ }
279
+ while ($month < 1) {
280
+ $year -= 1;
281
+ $month += 12;
282
+ }
266
283
  // check day overflow
267
- if (unit === 'day') {
268
- if ($day < 1) {
269
- while ($day < 1) {
270
- $month -= 1;
271
- if ($month < 1) {
272
- $year -= 1;
273
- $month += 12;
274
- }
275
- $day += LocalDate.getMonthLength($year, $month);
284
+ // Applies not only for 'day' unit, but also e.g 2022-05-31 plus 1 month should be 2022-06-30 (not 31!)
285
+ if ($day < 1) {
286
+ while ($day < 1) {
287
+ $month -= 1;
288
+ if ($month < 1) {
289
+ $year -= 1;
290
+ $month += 12;
291
+ }
292
+ $day += LocalDate.getMonthLength($year, $month);
293
+ }
294
+ }
295
+ else {
296
+ let monLen = LocalDate.getMonthLength($year, $month);
297
+ if (unit !== 'day') {
298
+ if ($day > monLen) {
299
+ // Case of 2022-05-31 plus 1 month should be 2022-06-30, not 31
300
+ $day = monLen;
276
301
  }
277
302
  }
278
303
  else {
279
- let monLen = LocalDate.getMonthLength($year, $month);
280
304
  while ($day > monLen) {
281
305
  $day -= monLen;
282
306
  $month += 1;
@@ -288,15 +312,6 @@ export class LocalDate {
288
312
  }
289
313
  }
290
314
  }
291
- // check month overflow
292
- while ($month > 12) {
293
- $year += 1;
294
- $month -= 12;
295
- }
296
- while ($month < 1) {
297
- $year -= 1;
298
- $month += 12;
299
- }
300
315
  if (mutate) {
301
316
  this.$year = $year;
302
317
  this.$month = $month;