@naturalcycles/js-lib 14.99.3 → 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.
- package/dist/datetime/localDate.js +37 -22
- package/dist/datetime/localTime.js +48 -58
- package/dist-esm/datetime/localDate.js +37 -22
- package/dist-esm/datetime/localTime.js +49 -58
- package/package.json +1 -1
- package/src/datetime/localDate.ts +42 -23
- package/src/datetime/localTime.ts +58 -64
|
@@ -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 ||
|
|
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
|
-
|
|
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
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
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;
|
|
@@ -177,14 +177,9 @@ class LocalTime {
|
|
|
177
177
|
}
|
|
178
178
|
setComponents(c, mutate = false) {
|
|
179
179
|
const d = mutate ? this.$date : new Date(this.$date);
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (c.month) {
|
|
184
|
-
d.setMonth(c.month - 1);
|
|
185
|
-
}
|
|
186
|
-
if (c.day) {
|
|
187
|
-
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());
|
|
188
183
|
}
|
|
189
184
|
if (c.hour !== undefined) {
|
|
190
185
|
d.setHours(c.hour);
|
|
@@ -202,6 +197,10 @@ class LocalTime {
|
|
|
202
197
|
num *= 7;
|
|
203
198
|
unit = 'day';
|
|
204
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
|
+
}
|
|
205
204
|
return this.set(unit, this.get(unit) + num, mutate);
|
|
206
205
|
}
|
|
207
206
|
subtract(num, unit, mutate = false) {
|
|
@@ -215,33 +214,14 @@ class LocalTime {
|
|
|
215
214
|
const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
|
|
216
215
|
if (!secDiff)
|
|
217
216
|
return 0;
|
|
218
|
-
if (unit === 'year' || unit === 'month') {
|
|
219
|
-
const sign = secDiff > 0 ? 1 : -1;
|
|
220
|
-
// Put items in descending order: "big minus small"
|
|
221
|
-
const [big, small] = sign === 1 ? [this.$date, date2] : [date2, this.$date];
|
|
222
|
-
if (unit === 'year') {
|
|
223
|
-
let years = big.getFullYear() - small.getFullYear();
|
|
224
|
-
const big2 = new Date(big);
|
|
225
|
-
const small2 = new Date(small);
|
|
226
|
-
big2.setFullYear(1584);
|
|
227
|
-
small2.setFullYear(1584);
|
|
228
|
-
if (big2 < small2)
|
|
229
|
-
years--;
|
|
230
|
-
return years * sign || 0;
|
|
231
|
-
}
|
|
232
|
-
if (unit === 'month') {
|
|
233
|
-
let months = (big.getFullYear() - small.getFullYear()) * 12 + big.getMonth() - small.getMonth();
|
|
234
|
-
const big2 = new Date(big);
|
|
235
|
-
const small2 = new Date(small);
|
|
236
|
-
big2.setFullYear(1584, 0);
|
|
237
|
-
small2.setFullYear(1584, 0);
|
|
238
|
-
if (big2 < small2)
|
|
239
|
-
months--;
|
|
240
|
-
return months * sign || 0;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
217
|
let r;
|
|
244
|
-
if (unit === '
|
|
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') {
|
|
245
225
|
r = secDiff / SECONDS_IN_DAY;
|
|
246
226
|
}
|
|
247
227
|
else if (unit === 'week') {
|
|
@@ -486,7 +466,7 @@ class LocalTime {
|
|
|
486
466
|
].join('');
|
|
487
467
|
}
|
|
488
468
|
toString() {
|
|
489
|
-
return
|
|
469
|
+
return this.toISODateTime();
|
|
490
470
|
}
|
|
491
471
|
toJSON() {
|
|
492
472
|
return this.unix();
|
|
@@ -543,29 +523,6 @@ function getWeekYear(date) {
|
|
|
543
523
|
return year - 1;
|
|
544
524
|
}
|
|
545
525
|
}
|
|
546
|
-
// function setWeekYear(
|
|
547
|
-
// date: Date,
|
|
548
|
-
// year: number,
|
|
549
|
-
// ): Date {
|
|
550
|
-
// const diff = differenceInCalendarDays(date, startOfWeekYear(date))
|
|
551
|
-
// const fourthOfJanuary = new Date(0)
|
|
552
|
-
// fourthOfJanuary.setFullYear(year, 0, 4)
|
|
553
|
-
// fourthOfJanuary.setHours(0, 0, 0, 0)
|
|
554
|
-
// date = startOfWeekYear(fourthOfJanuary)
|
|
555
|
-
// date.setDate(date.getDate() + diff)
|
|
556
|
-
// return date
|
|
557
|
-
// }
|
|
558
|
-
// function differenceInCalendarDays(
|
|
559
|
-
// dateLeft: Date,
|
|
560
|
-
// dateRight: Date,
|
|
561
|
-
// ): number {
|
|
562
|
-
// return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
|
|
563
|
-
// }
|
|
564
|
-
// function startOfDay(date: Date, mutate = false): Date {
|
|
565
|
-
// const d = mutate ? date : new Date(date)
|
|
566
|
-
// d.setHours(0, 0, 0, 0)
|
|
567
|
-
// return d
|
|
568
|
-
// }
|
|
569
526
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
570
527
|
function startOfWeek(date, mutate = false) {
|
|
571
528
|
const d = mutate ? date : new Date(date);
|
|
@@ -583,3 +540,36 @@ function endOfWeek(date, mutate = false) {
|
|
|
583
540
|
d.setDate(d.getDate() + diff);
|
|
584
541
|
return d;
|
|
585
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 ||
|
|
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
|
-
|
|
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
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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;
|
|
@@ -173,15 +173,11 @@ export class LocalTime {
|
|
|
173
173
|
return v === undefined ? this.get('second') : this.set('second', v);
|
|
174
174
|
}
|
|
175
175
|
setComponents(c, mutate = false) {
|
|
176
|
+
var _a;
|
|
176
177
|
const d = mutate ? this.$date : new Date(this.$date);
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (c.month) {
|
|
181
|
-
d.setMonth(c.month - 1);
|
|
182
|
-
}
|
|
183
|
-
if (c.day) {
|
|
184
|
-
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());
|
|
185
181
|
}
|
|
186
182
|
if (c.hour !== undefined) {
|
|
187
183
|
d.setHours(c.hour);
|
|
@@ -199,6 +195,10 @@ export class LocalTime {
|
|
|
199
195
|
num *= 7;
|
|
200
196
|
unit = 'day';
|
|
201
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
|
+
}
|
|
202
202
|
return this.set(unit, this.get(unit) + num, mutate);
|
|
203
203
|
}
|
|
204
204
|
subtract(num, unit, mutate = false) {
|
|
@@ -212,33 +212,14 @@ export class LocalTime {
|
|
|
212
212
|
const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
|
|
213
213
|
if (!secDiff)
|
|
214
214
|
return 0;
|
|
215
|
-
if (unit === 'year' || unit === 'month') {
|
|
216
|
-
const sign = secDiff > 0 ? 1 : -1;
|
|
217
|
-
// Put items in descending order: "big minus small"
|
|
218
|
-
const [big, small] = sign === 1 ? [this.$date, date2] : [date2, this.$date];
|
|
219
|
-
if (unit === 'year') {
|
|
220
|
-
let years = big.getFullYear() - small.getFullYear();
|
|
221
|
-
const big2 = new Date(big);
|
|
222
|
-
const small2 = new Date(small);
|
|
223
|
-
big2.setFullYear(1584);
|
|
224
|
-
small2.setFullYear(1584);
|
|
225
|
-
if (big2 < small2)
|
|
226
|
-
years--;
|
|
227
|
-
return years * sign || 0;
|
|
228
|
-
}
|
|
229
|
-
if (unit === 'month') {
|
|
230
|
-
let months = (big.getFullYear() - small.getFullYear()) * 12 + big.getMonth() - small.getMonth();
|
|
231
|
-
const big2 = new Date(big);
|
|
232
|
-
const small2 = new Date(small);
|
|
233
|
-
big2.setFullYear(1584, 0);
|
|
234
|
-
small2.setFullYear(1584, 0);
|
|
235
|
-
if (big2 < small2)
|
|
236
|
-
months--;
|
|
237
|
-
return months * sign || 0;
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
215
|
let r;
|
|
241
|
-
if (unit === '
|
|
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') {
|
|
242
223
|
r = secDiff / SECONDS_IN_DAY;
|
|
243
224
|
}
|
|
244
225
|
else if (unit === 'week') {
|
|
@@ -483,7 +464,7 @@ export class LocalTime {
|
|
|
483
464
|
].join('');
|
|
484
465
|
}
|
|
485
466
|
toString() {
|
|
486
|
-
return
|
|
467
|
+
return this.toISODateTime();
|
|
487
468
|
}
|
|
488
469
|
toJSON() {
|
|
489
470
|
return this.unix();
|
|
@@ -538,29 +519,6 @@ function getWeekYear(date) {
|
|
|
538
519
|
return year - 1;
|
|
539
520
|
}
|
|
540
521
|
}
|
|
541
|
-
// function setWeekYear(
|
|
542
|
-
// date: Date,
|
|
543
|
-
// year: number,
|
|
544
|
-
// ): Date {
|
|
545
|
-
// const diff = differenceInCalendarDays(date, startOfWeekYear(date))
|
|
546
|
-
// const fourthOfJanuary = new Date(0)
|
|
547
|
-
// fourthOfJanuary.setFullYear(year, 0, 4)
|
|
548
|
-
// fourthOfJanuary.setHours(0, 0, 0, 0)
|
|
549
|
-
// date = startOfWeekYear(fourthOfJanuary)
|
|
550
|
-
// date.setDate(date.getDate() + diff)
|
|
551
|
-
// return date
|
|
552
|
-
// }
|
|
553
|
-
// function differenceInCalendarDays(
|
|
554
|
-
// dateLeft: Date,
|
|
555
|
-
// dateRight: Date,
|
|
556
|
-
// ): number {
|
|
557
|
-
// return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
|
|
558
|
-
// }
|
|
559
|
-
// function startOfDay(date: Date, mutate = false): Date {
|
|
560
|
-
// const d = mutate ? date : new Date(date)
|
|
561
|
-
// d.setHours(0, 0, 0, 0)
|
|
562
|
-
// return d
|
|
563
|
-
// }
|
|
564
522
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
565
523
|
function startOfWeek(date, mutate = false) {
|
|
566
524
|
const d = mutate ? date : new Date(date);
|
|
@@ -578,3 +536,36 @@ function endOfWeek(date, mutate = false) {
|
|
|
578
536
|
d.setDate(d.getDate() + diff);
|
|
579
537
|
return d;
|
|
580
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
|
@@ -269,7 +269,15 @@ export class LocalDate {
|
|
|
269
269
|
if (unit === 'year') {
|
|
270
270
|
let years = big.$year - small.$year
|
|
271
271
|
|
|
272
|
-
if (
|
|
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)
|
|
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
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
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
|
-
|
|
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
|
|
@@ -229,15 +229,15 @@ export class LocalTime {
|
|
|
229
229
|
setComponents(c: Partial<LocalTimeComponents>, mutate = false): LocalTime {
|
|
230
230
|
const d = mutate ? this.$date : new Date(this.$date)
|
|
231
231
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
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
|
+
)
|
|
240
239
|
}
|
|
240
|
+
|
|
241
241
|
if (c.hour !== undefined) {
|
|
242
242
|
d.setHours(c.hour)
|
|
243
243
|
}
|
|
@@ -256,6 +256,12 @@ export class LocalTime {
|
|
|
256
256
|
num *= 7
|
|
257
257
|
unit = 'day'
|
|
258
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
|
+
|
|
259
265
|
return this.set(unit, this.get(unit) + num, mutate)
|
|
260
266
|
}
|
|
261
267
|
|
|
@@ -273,37 +279,13 @@ export class LocalTime {
|
|
|
273
279
|
const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000
|
|
274
280
|
if (!secDiff) return 0
|
|
275
281
|
|
|
276
|
-
if (unit === 'year' || unit === 'month') {
|
|
277
|
-
const sign = secDiff > 0 ? 1 : -1
|
|
278
|
-
|
|
279
|
-
// Put items in descending order: "big minus small"
|
|
280
|
-
const [big, small] = sign === 1 ? [this.$date, date2] : [date2, this.$date]
|
|
281
|
-
|
|
282
|
-
if (unit === 'year') {
|
|
283
|
-
let years = big.getFullYear() - small.getFullYear()
|
|
284
|
-
const big2 = new Date(big)
|
|
285
|
-
const small2 = new Date(small)
|
|
286
|
-
big2.setFullYear(1584)
|
|
287
|
-
small2.setFullYear(1584)
|
|
288
|
-
if (big2 < small2) years--
|
|
289
|
-
return years * sign || 0
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (unit === 'month') {
|
|
293
|
-
let months =
|
|
294
|
-
(big.getFullYear() - small.getFullYear()) * 12 + big.getMonth() - small.getMonth()
|
|
295
|
-
const big2 = new Date(big)
|
|
296
|
-
const small2 = new Date(small)
|
|
297
|
-
big2.setFullYear(1584, 0)
|
|
298
|
-
small2.setFullYear(1584, 0)
|
|
299
|
-
if (big2 < small2) months--
|
|
300
|
-
return months * sign || 0
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
282
|
let r
|
|
305
283
|
|
|
306
|
-
if (unit === '
|
|
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') {
|
|
307
289
|
r = secDiff / SECONDS_IN_DAY
|
|
308
290
|
} else if (unit === 'week') {
|
|
309
291
|
r = secDiff / (7 * 24 * 60 * 60)
|
|
@@ -587,7 +569,7 @@ export class LocalTime {
|
|
|
587
569
|
}
|
|
588
570
|
|
|
589
571
|
toString(): string {
|
|
590
|
-
return
|
|
572
|
+
return this.toISODateTime()
|
|
591
573
|
}
|
|
592
574
|
|
|
593
575
|
toJSON(): UnixTimestampNumber {
|
|
@@ -651,32 +633,6 @@ function getWeekYear(date: Date): number {
|
|
|
651
633
|
}
|
|
652
634
|
}
|
|
653
635
|
|
|
654
|
-
// function setWeekYear(
|
|
655
|
-
// date: Date,
|
|
656
|
-
// year: number,
|
|
657
|
-
// ): Date {
|
|
658
|
-
// const diff = differenceInCalendarDays(date, startOfWeekYear(date))
|
|
659
|
-
// const fourthOfJanuary = new Date(0)
|
|
660
|
-
// fourthOfJanuary.setFullYear(year, 0, 4)
|
|
661
|
-
// fourthOfJanuary.setHours(0, 0, 0, 0)
|
|
662
|
-
// date = startOfWeekYear(fourthOfJanuary)
|
|
663
|
-
// date.setDate(date.getDate() + diff)
|
|
664
|
-
// return date
|
|
665
|
-
// }
|
|
666
|
-
|
|
667
|
-
// function differenceInCalendarDays(
|
|
668
|
-
// dateLeft: Date,
|
|
669
|
-
// dateRight: Date,
|
|
670
|
-
// ): number {
|
|
671
|
-
// return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
|
|
672
|
-
// }
|
|
673
|
-
|
|
674
|
-
// function startOfDay(date: Date, mutate = false): Date {
|
|
675
|
-
// const d = mutate ? date : new Date(date)
|
|
676
|
-
// d.setHours(0, 0, 0, 0)
|
|
677
|
-
// return d
|
|
678
|
-
// }
|
|
679
|
-
|
|
680
636
|
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
681
637
|
function startOfWeek(date: Date, mutate = false): Date {
|
|
682
638
|
const d = mutate ? date : new Date(date)
|
|
@@ -699,3 +655,41 @@ function endOfWeek(date: Date, mutate = false): Date {
|
|
|
699
655
|
d.setDate(d.getDate() + diff)
|
|
700
656
|
return d
|
|
701
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
|
+
}
|