@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.
- package/dist/datetime/localDate.js +37 -22
- package/dist/datetime/localTime.d.ts +0 -3
- package/dist/datetime/localTime.js +80 -120
- package/dist-esm/datetime/localDate.js +37 -22
- package/dist-esm/datetime/localTime.js +81 -120
- package/package.json +1 -1
- package/src/datetime/localDate.ts +42 -23
- package/src/datetime/localTime.ts +92 -133
|
@@ -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;
|
|
@@ -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
|
|
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
|
|
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()
|
|
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
|
|
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
|
|
103
|
+
return this.$date.getFullYear();
|
|
113
104
|
}
|
|
114
105
|
if (unit === 'month') {
|
|
115
|
-
return
|
|
106
|
+
return this.$date.getMonth() + 1;
|
|
116
107
|
}
|
|
117
108
|
if (unit === 'day') {
|
|
118
|
-
return this
|
|
109
|
+
return this.$date.getDate();
|
|
119
110
|
}
|
|
120
111
|
if (unit === 'hour') {
|
|
121
|
-
return this
|
|
112
|
+
return this.$date.getHours();
|
|
122
113
|
}
|
|
123
114
|
if (unit === 'minute') {
|
|
124
|
-
return this
|
|
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
|
|
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
|
-
|
|
126
|
+
t.$date.setFullYear(v);
|
|
137
127
|
}
|
|
138
128
|
else if (unit === 'month') {
|
|
139
|
-
|
|
129
|
+
t.$date.setMonth(v - 1);
|
|
140
130
|
}
|
|
141
131
|
else if (unit === 'day') {
|
|
142
|
-
|
|
132
|
+
t.$date.setDate(v);
|
|
143
133
|
}
|
|
144
134
|
else if (unit === 'hour') {
|
|
145
|
-
|
|
135
|
+
t.$date.setHours(v);
|
|
146
136
|
}
|
|
147
137
|
else if (unit === 'minute') {
|
|
148
|
-
|
|
138
|
+
t.$date.setMinutes(v);
|
|
149
139
|
}
|
|
150
140
|
else if (unit === 'second') {
|
|
151
|
-
|
|
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
|
-
|
|
192
|
-
if (c.year) {
|
|
193
|
-
|
|
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
|
-
|
|
185
|
+
d.setHours(c.hour);
|
|
203
186
|
}
|
|
204
187
|
if (c.minute !== undefined) {
|
|
205
|
-
|
|
188
|
+
d.setMinutes(c.minute);
|
|
206
189
|
}
|
|
207
190
|
if (c.second !== undefined) {
|
|
208
|
-
|
|
191
|
+
d.setSeconds(c.second);
|
|
209
192
|
}
|
|
210
|
-
|
|
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 === '
|
|
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
|
-
|
|
249
|
+
d.setMinutes(0);
|
|
284
250
|
if (unit !== 'hour') {
|
|
285
|
-
|
|
251
|
+
d.setHours(0);
|
|
286
252
|
if (unit !== 'day') {
|
|
287
253
|
// year, month or week
|
|
288
254
|
if (unit === 'year') {
|
|
289
|
-
|
|
290
|
-
|
|
255
|
+
d.setMonth(0);
|
|
256
|
+
d.setDate(1);
|
|
291
257
|
}
|
|
292
258
|
else if (unit === 'month') {
|
|
293
|
-
|
|
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
|
-
|
|
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
|
-
|
|
276
|
+
d.setMinutes(59);
|
|
313
277
|
if (unit !== 'hour') {
|
|
314
|
-
|
|
278
|
+
d.setHours(23);
|
|
315
279
|
if (unit !== 'day') {
|
|
316
280
|
// year, month or week
|
|
317
281
|
if (unit === 'year') {
|
|
318
|
-
|
|
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
|
-
|
|
290
|
+
d.setDate(lastDay);
|
|
327
291
|
}
|
|
328
292
|
}
|
|
329
293
|
}
|
|
330
294
|
}
|
|
331
|
-
|
|
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)
|
|
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
|
|
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 ||
|
|
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;
|