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