@naturalcycles/js-lib 14.98.1 → 14.99.0
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/array/array.util.d.ts +10 -1
- package/dist/array/array.util.js +36 -2
- package/dist/datetime/localDate.d.ts +17 -10
- package/dist/datetime/localDate.js +27 -3
- package/dist/datetime/localTime.d.ts +25 -6
- package/dist/datetime/localTime.js +172 -9
- package/dist/index.d.ts +4 -4
- package/dist/index.js +1 -0
- package/dist/types.d.ts +5 -2
- package/dist/vendor/is.d.ts +2 -0
- package/dist-esm/array/array.util.js +30 -1
- package/dist-esm/datetime/localDate.js +27 -3
- package/dist-esm/datetime/localTime.js +171 -8
- package/dist-esm/index.js +1 -0
- package/package.json +2 -2
- package/src/array/array.util.ts +30 -1
- package/src/datetime/localDate.ts +44 -13
- package/src/datetime/localTime.ts +203 -15
- package/src/index.ts +20 -2
- package/src/promise/pRetry.ts +2 -2
- package/src/types.ts +9 -2
|
@@ -87,16 +87,24 @@ export class LocalDate {
|
|
|
87
87
|
}
|
|
88
88
|
static earliest(items) {
|
|
89
89
|
_assert(items.length, 'LocalDate.earliest called on empty array');
|
|
90
|
-
return items
|
|
90
|
+
return items
|
|
91
|
+
.map(i => LocalDate.of(i))
|
|
92
|
+
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
91
93
|
}
|
|
92
94
|
static latestOrUndefined(items) {
|
|
93
95
|
return items.length ? LocalDate.latest(items) : undefined;
|
|
94
96
|
}
|
|
95
97
|
static latest(items) {
|
|
96
98
|
_assert(items.length, 'LocalDate.latest called on empty array');
|
|
97
|
-
return items
|
|
99
|
+
return items
|
|
100
|
+
.map(i => LocalDate.of(i))
|
|
101
|
+
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
98
102
|
}
|
|
99
103
|
static range(min, max, incl = '[)', step = 1, stepUnit = 'day') {
|
|
104
|
+
if (stepUnit === 'week') {
|
|
105
|
+
step *= 7;
|
|
106
|
+
stepUnit = 'day';
|
|
107
|
+
}
|
|
100
108
|
const dates = [];
|
|
101
109
|
const $min = LocalDate.of(min);
|
|
102
110
|
const $max = LocalDate.of(max).startOf(stepUnit);
|
|
@@ -206,7 +214,7 @@ export class LocalDate {
|
|
|
206
214
|
if (unit === 'month') {
|
|
207
215
|
return (this.$year - d.$year) * 12 + (this.$month - d.$month);
|
|
208
216
|
}
|
|
209
|
-
// unit is 'day'
|
|
217
|
+
// unit is 'day' or 'week'
|
|
210
218
|
let days = this.$day - d.$day;
|
|
211
219
|
if (d.$year < this.$year) {
|
|
212
220
|
for (let year = d.$year; year < this.$year; year++) {
|
|
@@ -228,10 +236,17 @@ export class LocalDate {
|
|
|
228
236
|
days -= LocalDate.getMonthLength(d.$year, month);
|
|
229
237
|
}
|
|
230
238
|
}
|
|
239
|
+
if (unit === 'week') {
|
|
240
|
+
return Math.floor(days / 7);
|
|
241
|
+
}
|
|
231
242
|
return days;
|
|
232
243
|
}
|
|
233
244
|
add(num, unit, mutate = false) {
|
|
234
245
|
let { $day, $month, $year } = this;
|
|
246
|
+
if (unit === 'week') {
|
|
247
|
+
num *= 7;
|
|
248
|
+
unit = 'day';
|
|
249
|
+
}
|
|
235
250
|
if (unit === 'day') {
|
|
236
251
|
$day += num;
|
|
237
252
|
}
|
|
@@ -331,6 +346,12 @@ export class LocalDate {
|
|
|
331
346
|
toISODate() {
|
|
332
347
|
return this.toString();
|
|
333
348
|
}
|
|
349
|
+
/**
|
|
350
|
+
* Returns e.g: `1984-06-21T17:56:21`
|
|
351
|
+
*/
|
|
352
|
+
toISODateTime() {
|
|
353
|
+
return this.toString() + 'T00:00:00';
|
|
354
|
+
}
|
|
334
355
|
toString() {
|
|
335
356
|
return [
|
|
336
357
|
String(this.$year).padStart(4, '0'),
|
|
@@ -355,6 +376,9 @@ export class LocalDate {
|
|
|
355
376
|
toJSON() {
|
|
356
377
|
return this.toString();
|
|
357
378
|
}
|
|
379
|
+
format(fmt) {
|
|
380
|
+
return fmt(this);
|
|
381
|
+
}
|
|
358
382
|
}
|
|
359
383
|
/**
|
|
360
384
|
* Shortcut wrapper around `LocalDate.parse` / `LocalDate.today`
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import { _assert } from '../error/assert';
|
|
2
2
|
import { _ms } from '../time/time.util';
|
|
3
3
|
import { LocalDate } from './localDate';
|
|
4
|
+
export var ISODayOfWeek;
|
|
5
|
+
(function (ISODayOfWeek) {
|
|
6
|
+
ISODayOfWeek[ISODayOfWeek["MONDAY"] = 1] = "MONDAY";
|
|
7
|
+
ISODayOfWeek[ISODayOfWeek["TUESDAY"] = 2] = "TUESDAY";
|
|
8
|
+
ISODayOfWeek[ISODayOfWeek["WEDNESDAY"] = 3] = "WEDNESDAY";
|
|
9
|
+
ISODayOfWeek[ISODayOfWeek["THURSDAY"] = 4] = "THURSDAY";
|
|
10
|
+
ISODayOfWeek[ISODayOfWeek["FRIDAY"] = 5] = "FRIDAY";
|
|
11
|
+
ISODayOfWeek[ISODayOfWeek["SATURDAY"] = 6] = "SATURDAY";
|
|
12
|
+
ISODayOfWeek[ISODayOfWeek["SUNDAY"] = 7] = "SUNDAY";
|
|
13
|
+
})(ISODayOfWeek || (ISODayOfWeek = {}));
|
|
14
|
+
const weekStartsOn = 1; // mon, as per ISO
|
|
15
|
+
const MILLISECONDS_IN_WEEK = 604800000;
|
|
16
|
+
// const MILLISECONDS_IN_DAY = 86400000
|
|
17
|
+
// const MILLISECONDS_IN_MINUTE = 60000
|
|
18
|
+
const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
|
|
4
19
|
/* eslint-disable no-dupe-class-members */
|
|
5
20
|
/**
|
|
6
21
|
* @experimental
|
|
@@ -104,6 +119,9 @@ export class LocalTime {
|
|
|
104
119
|
if (unit === 'minute') {
|
|
105
120
|
return this.utcMode ? this.$date.getUTCMinutes() : this.$date.getMinutes();
|
|
106
121
|
}
|
|
122
|
+
if (unit === 'week') {
|
|
123
|
+
return getWeek(this.$date);
|
|
124
|
+
}
|
|
107
125
|
// second
|
|
108
126
|
return this.utcMode ? this.$date.getUTCSeconds() : this.$date.getSeconds();
|
|
109
127
|
}
|
|
@@ -128,6 +146,9 @@ export class LocalTime {
|
|
|
128
146
|
else if (unit === 'second') {
|
|
129
147
|
this.utcMode ? t.$date.setUTCSeconds(v) : t.$date.setSeconds(v);
|
|
130
148
|
}
|
|
149
|
+
else if (unit === 'week') {
|
|
150
|
+
setWeek(t.$date, v, true);
|
|
151
|
+
}
|
|
131
152
|
/* eslint-enable @typescript-eslint/no-unused-expressions */
|
|
132
153
|
return t;
|
|
133
154
|
}
|
|
@@ -137,9 +158,21 @@ export class LocalTime {
|
|
|
137
158
|
month(v) {
|
|
138
159
|
return v === undefined ? this.get('month') : this.set('month', v);
|
|
139
160
|
}
|
|
161
|
+
week(v) {
|
|
162
|
+
return v === undefined ? getWeek(this.$date) : this.set('week', v);
|
|
163
|
+
}
|
|
140
164
|
day(v) {
|
|
141
165
|
return v === undefined ? this.get('day') : this.set('day', v);
|
|
142
166
|
}
|
|
167
|
+
dayOfWeek(v) {
|
|
168
|
+
const dow = (this.$date.getDay() || 7);
|
|
169
|
+
if (v === undefined) {
|
|
170
|
+
return dow;
|
|
171
|
+
}
|
|
172
|
+
if (!VALID_DAYS_OF_WEEK.has(v))
|
|
173
|
+
throw new Error(`Invalid dayOfWeek: ${v}`);
|
|
174
|
+
return this.add(v - dow, 'day');
|
|
175
|
+
}
|
|
143
176
|
hour(v) {
|
|
144
177
|
return v === undefined ? this.get('hour') : this.set('hour', v);
|
|
145
178
|
}
|
|
@@ -174,6 +207,10 @@ export class LocalTime {
|
|
|
174
207
|
return mutate ? this : new LocalTime(d, this.utcMode);
|
|
175
208
|
}
|
|
176
209
|
add(num, unit, mutate = false) {
|
|
210
|
+
if (unit === 'week') {
|
|
211
|
+
num *= 7;
|
|
212
|
+
unit = 'day';
|
|
213
|
+
}
|
|
177
214
|
return this.set(unit, this.get(unit) + num, mutate);
|
|
178
215
|
}
|
|
179
216
|
subtract(num, unit, mutate = false) {
|
|
@@ -197,6 +234,9 @@ export class LocalTime {
|
|
|
197
234
|
if (unit === 'day') {
|
|
198
235
|
r = secDiff / (24 * 60 * 60);
|
|
199
236
|
}
|
|
237
|
+
else if (unit === 'week') {
|
|
238
|
+
r = secDiff / (7 * 24 * 60 * 60);
|
|
239
|
+
}
|
|
200
240
|
else if (unit === 'hour') {
|
|
201
241
|
r = secDiff / (60 * 60);
|
|
202
242
|
}
|
|
@@ -207,7 +247,7 @@ export class LocalTime {
|
|
|
207
247
|
// unit === 'second'
|
|
208
248
|
r = secDiff;
|
|
209
249
|
}
|
|
210
|
-
r =
|
|
250
|
+
r = Math.trunc(r);
|
|
211
251
|
if (Object.is(r, -0))
|
|
212
252
|
return 0;
|
|
213
253
|
return r;
|
|
@@ -216,16 +256,53 @@ export class LocalTime {
|
|
|
216
256
|
if (unit === 'second')
|
|
217
257
|
return this;
|
|
218
258
|
const d = mutate ? this.$date : new Date(this.$date);
|
|
259
|
+
d.setSeconds(0, 0);
|
|
219
260
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
220
|
-
this.utcMode ? d.setUTCSeconds(0) : d.setSeconds(0);
|
|
221
261
|
if (unit !== 'minute') {
|
|
222
262
|
this.utcMode ? d.setUTCMinutes(0) : d.setMinutes(0);
|
|
223
263
|
if (unit !== 'hour') {
|
|
224
264
|
this.utcMode ? d.setUTCHours(0) : d.setHours(0);
|
|
225
265
|
if (unit !== 'day') {
|
|
226
|
-
|
|
227
|
-
if (unit
|
|
266
|
+
// year, month or week
|
|
267
|
+
if (unit === 'year') {
|
|
228
268
|
this.utcMode ? d.setUTCMonth(0) : d.setMonth(0);
|
|
269
|
+
this.utcMode ? d.setUTCDate(1) : d.setDate(1);
|
|
270
|
+
}
|
|
271
|
+
else if (unit === 'month') {
|
|
272
|
+
this.utcMode ? d.setUTCDate(1) : d.setDate(1);
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
// week
|
|
276
|
+
startOfWeek(d, true);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/* eslint-enable @typescript-eslint/no-unused-expressions */
|
|
282
|
+
return mutate ? this : new LocalTime(d, this.utcMode);
|
|
283
|
+
}
|
|
284
|
+
endOf(unit, mutate = false) {
|
|
285
|
+
if (unit === 'second')
|
|
286
|
+
return this;
|
|
287
|
+
const d = mutate ? this.$date : new Date(this.$date);
|
|
288
|
+
d.setSeconds(59, 0);
|
|
289
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
|
290
|
+
if (unit !== 'minute') {
|
|
291
|
+
this.utcMode ? d.setUTCMinutes(59) : d.setMinutes(59);
|
|
292
|
+
if (unit !== 'hour') {
|
|
293
|
+
this.utcMode ? d.setUTCHours(23) : d.setHours(23);
|
|
294
|
+
if (unit !== 'day') {
|
|
295
|
+
// year, month or week
|
|
296
|
+
if (unit === 'year') {
|
|
297
|
+
this.utcMode ? d.setUTCMonth(11) : d.setMonth(11);
|
|
298
|
+
}
|
|
299
|
+
if (unit === 'week') {
|
|
300
|
+
endOfWeek(d, true);
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
// year or month
|
|
304
|
+
const lastDay = LocalDate.getMonthLength(d.getFullYear(), d.getMonth() + 1);
|
|
305
|
+
this.utcMode ? d.setUTCDate(lastDay) : d.setDate(lastDay);
|
|
229
306
|
}
|
|
230
307
|
}
|
|
231
308
|
}
|
|
@@ -248,14 +325,18 @@ export class LocalTime {
|
|
|
248
325
|
}
|
|
249
326
|
static earliest(items) {
|
|
250
327
|
_assert(items.length, 'LocalTime.earliest called on empty array');
|
|
251
|
-
return items
|
|
328
|
+
return items
|
|
329
|
+
.map(i => LocalTime.of(i))
|
|
330
|
+
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
|
|
252
331
|
}
|
|
253
332
|
static latestOrUndefined(items) {
|
|
254
333
|
return items.length ? LocalTime.latest(items) : undefined;
|
|
255
334
|
}
|
|
256
335
|
static latest(items) {
|
|
257
336
|
_assert(items.length, 'LocalTime.latest called on empty array');
|
|
258
|
-
return items
|
|
337
|
+
return items
|
|
338
|
+
.map(i => LocalTime.of(i))
|
|
339
|
+
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
259
340
|
}
|
|
260
341
|
isSame(d) {
|
|
261
342
|
return this.cmp(d) === 0;
|
|
@@ -295,7 +376,6 @@ export class LocalTime {
|
|
|
295
376
|
return 0;
|
|
296
377
|
return t1 < t2 ? -1 : 1;
|
|
297
378
|
}
|
|
298
|
-
// todo: endOf
|
|
299
379
|
components() {
|
|
300
380
|
if (this.utcMode) {
|
|
301
381
|
return {
|
|
@@ -368,7 +448,7 @@ export class LocalTime {
|
|
|
368
448
|
// .join(' ')
|
|
369
449
|
}
|
|
370
450
|
/**
|
|
371
|
-
* Returns e.g: `1984-06-21T17:56:21
|
|
451
|
+
* Returns e.g: `1984-06-21T17:56:21`
|
|
372
452
|
*/
|
|
373
453
|
toISODateTime() {
|
|
374
454
|
return this.$date.toISOString().slice(0, 19);
|
|
@@ -420,6 +500,9 @@ export class LocalTime {
|
|
|
420
500
|
toJSON() {
|
|
421
501
|
return this.unix();
|
|
422
502
|
}
|
|
503
|
+
format(fmt) {
|
|
504
|
+
return fmt(this);
|
|
505
|
+
}
|
|
423
506
|
}
|
|
424
507
|
/**
|
|
425
508
|
* Shortcut wrapper around `LocalDate.parse` / `LocalDate.today`
|
|
@@ -427,3 +510,83 @@ export class LocalTime {
|
|
|
427
510
|
export function localTime(d) {
|
|
428
511
|
return d ? LocalTime.of(d) : LocalTime.now();
|
|
429
512
|
}
|
|
513
|
+
// based on: https://github.com/date-fns/date-fns/blob/master/src/getISOWeek/index.ts
|
|
514
|
+
function getWeek(date) {
|
|
515
|
+
const diff = startOfWeek(date).getTime() - startOfWeekYear(date).getTime();
|
|
516
|
+
return Math.round(diff / MILLISECONDS_IN_WEEK) + 1;
|
|
517
|
+
}
|
|
518
|
+
function setWeek(date, week, mutate = false) {
|
|
519
|
+
const d = mutate ? date : new Date(date);
|
|
520
|
+
const diff = getWeek(d) - week;
|
|
521
|
+
d.setDate(d.getDate() - diff * 7);
|
|
522
|
+
return d;
|
|
523
|
+
}
|
|
524
|
+
// based on: https://github.com/date-fns/date-fns/blob/master/src/startOfISOWeekYear/index.ts
|
|
525
|
+
function startOfWeekYear(date) {
|
|
526
|
+
const year = getWeekYear(date);
|
|
527
|
+
const fourthOfJanuary = new Date(0);
|
|
528
|
+
fourthOfJanuary.setFullYear(year, 0, 4);
|
|
529
|
+
fourthOfJanuary.setHours(0, 0, 0, 0);
|
|
530
|
+
return startOfWeek(fourthOfJanuary, true);
|
|
531
|
+
}
|
|
532
|
+
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/getISOWeekYear/index.ts
|
|
533
|
+
function getWeekYear(date) {
|
|
534
|
+
const year = date.getFullYear();
|
|
535
|
+
const fourthOfJanuaryOfNextYear = new Date(0);
|
|
536
|
+
fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
|
|
537
|
+
fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
|
|
538
|
+
const startOfNextYear = startOfWeek(fourthOfJanuaryOfNextYear, true);
|
|
539
|
+
const fourthOfJanuaryOfThisYear = new Date(0);
|
|
540
|
+
fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
|
|
541
|
+
fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
|
|
542
|
+
const startOfThisYear = startOfWeek(fourthOfJanuaryOfThisYear, true);
|
|
543
|
+
if (date.getTime() >= startOfNextYear.getTime()) {
|
|
544
|
+
return year + 1;
|
|
545
|
+
}
|
|
546
|
+
else if (date.getTime() >= startOfThisYear.getTime()) {
|
|
547
|
+
return year;
|
|
548
|
+
}
|
|
549
|
+
else {
|
|
550
|
+
return year - 1;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// function setWeekYear(
|
|
554
|
+
// date: Date,
|
|
555
|
+
// year: number,
|
|
556
|
+
// ): Date {
|
|
557
|
+
// const diff = differenceInCalendarDays(date, startOfWeekYear(date))
|
|
558
|
+
// const fourthOfJanuary = new Date(0)
|
|
559
|
+
// fourthOfJanuary.setFullYear(year, 0, 4)
|
|
560
|
+
// fourthOfJanuary.setHours(0, 0, 0, 0)
|
|
561
|
+
// date = startOfWeekYear(fourthOfJanuary)
|
|
562
|
+
// date.setDate(date.getDate() + diff)
|
|
563
|
+
// return date
|
|
564
|
+
// }
|
|
565
|
+
// function differenceInCalendarDays(
|
|
566
|
+
// dateLeft: Date,
|
|
567
|
+
// dateRight: Date,
|
|
568
|
+
// ): number {
|
|
569
|
+
// return Math.round((startOfDay(dateLeft).getTime() - startOfDay(dateRight).getTime()) / MILLISECONDS_IN_DAY)
|
|
570
|
+
// }
|
|
571
|
+
// function startOfDay(date: Date, mutate = false): Date {
|
|
572
|
+
// const d = mutate ? date : new Date(date)
|
|
573
|
+
// d.setHours(0, 0, 0, 0)
|
|
574
|
+
// return d
|
|
575
|
+
// }
|
|
576
|
+
// based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
|
|
577
|
+
function startOfWeek(date, mutate = false) {
|
|
578
|
+
const d = mutate ? date : new Date(date);
|
|
579
|
+
const day = d.getDay();
|
|
580
|
+
const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
|
|
581
|
+
d.setDate(d.getDate() - diff);
|
|
582
|
+
d.setHours(0, 0, 0, 0);
|
|
583
|
+
return d;
|
|
584
|
+
}
|
|
585
|
+
// based on: https://github.com/date-fns/date-fns/blob/master/src/endOfWeek/index.ts
|
|
586
|
+
function endOfWeek(date, mutate = false) {
|
|
587
|
+
const d = mutate ? date : new Date(date);
|
|
588
|
+
const day = d.getDay();
|
|
589
|
+
const diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn);
|
|
590
|
+
d.setDate(d.getDate() + diff);
|
|
591
|
+
return d;
|
|
592
|
+
}
|
package/dist-esm/index.js
CHANGED
|
@@ -60,4 +60,5 @@ export * from './datetime/localDate';
|
|
|
60
60
|
export * from './datetime/localTime';
|
|
61
61
|
export * from './datetime/dateInterval';
|
|
62
62
|
export * from './datetime/timeInterval';
|
|
63
|
+
import { ISODayOfWeek, } from './datetime/localTime';
|
|
63
64
|
export { is, _createPromiseDecorator, _stringMapValues, _stringMapEntries, _objectKeys, pMap, _passthroughMapper, _passUndefinedMapper, _passthroughPredicate, _passNothingPredicate, _noop, ErrorMode, pDefer, AggregatedError, pRetry, pRetryFn, pTimeout, pTimeoutFn, _tryCatch, _TryCatch, _stringifyAny, jsonSchema, JsonSchemaAnyBuilder, commonLoggerMinLevel, commonLoggerNoop, commonLogLevelNumber, commonLoggerPipe, commonLoggerPrefix, commonLoggerCreate, PQueue, END, SKIP, };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@naturalcycles/js-lib",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.99.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"prepare": "husky install",
|
|
6
6
|
"build-prod": "build-prod-esm-cjs",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@naturalcycles/nodejs-lib": "^12.33.4",
|
|
17
17
|
"@naturalcycles/time-lib": "^3.5.1",
|
|
18
18
|
"@types/node": "^17.0.4",
|
|
19
|
-
"jest": "^
|
|
19
|
+
"jest": "^28.0.3",
|
|
20
20
|
"patch-package": "^6.2.1",
|
|
21
21
|
"prettier": "^2.1.2",
|
|
22
22
|
"rxjs": "^7.0.1",
|
package/src/array/array.util.ts
CHANGED
|
@@ -272,9 +272,38 @@ export function _shuffle<T>(array: T[], mutate = false): T[] {
|
|
|
272
272
|
return a
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
+
/**
|
|
276
|
+
* Returns last item of non-empty array.
|
|
277
|
+
* Throws if array is empty.
|
|
278
|
+
*/
|
|
279
|
+
export function _last<T>(array: T[]): T {
|
|
280
|
+
if (!array.length) throw new Error('_last called on empty array')
|
|
281
|
+
return array[array.length - 1]!
|
|
282
|
+
}
|
|
283
|
+
|
|
275
284
|
/**
|
|
276
285
|
* Returns last item of the array (or undefined if array is empty).
|
|
277
286
|
*/
|
|
278
|
-
export function
|
|
287
|
+
export function _lastOrUndefined<T>(array: T[]): T | undefined {
|
|
279
288
|
return array[array.length - 1]
|
|
280
289
|
}
|
|
290
|
+
|
|
291
|
+
export function _minOrUndefined<T>(array: T[]): T | undefined {
|
|
292
|
+
if (!array.length) return
|
|
293
|
+
return _min(array)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
export function _min<T>(array: T[]): T {
|
|
297
|
+
if (!array.length) throw new Error('_min called on empty array')
|
|
298
|
+
return array.reduce((min, item) => (min <= item ? min : item))
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
export function _maxOrUndefined<T>(array: T[]): T | undefined {
|
|
302
|
+
if (!array.length) return
|
|
303
|
+
return _max(array)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function _max<T>(array: T[]): T {
|
|
307
|
+
if (!array.length) throw new Error('_max called on empty array')
|
|
308
|
+
return array.reduce((max, item) => (max >= item ? max : item))
|
|
309
|
+
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { _assert } from '../error/assert'
|
|
2
|
-
import { IsoDateString, UnixTimestampNumber } from '../types'
|
|
2
|
+
import { IsoDateString, IsoDateTimeString, UnixTimestampNumber } from '../types'
|
|
3
3
|
import { LocalTime } from './localTime'
|
|
4
4
|
|
|
5
|
-
export type LocalDateUnit =
|
|
5
|
+
export type LocalDateUnit = LocalDateUnitStrict | 'week'
|
|
6
|
+
export type LocalDateUnitStrict = 'year' | 'month' | 'day'
|
|
6
7
|
export type Inclusiveness = '()' | '[]' | '[)' | '(]'
|
|
7
8
|
|
|
8
9
|
const MDAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
|
9
10
|
const DATE_REGEX = /^(\d\d\d\d)-(\d\d)-(\d\d)$/
|
|
10
11
|
|
|
11
12
|
export type LocalDateConfig = LocalDate | IsoDateString
|
|
13
|
+
export type LocalDateFormatter = (ld: LocalDate) => string
|
|
12
14
|
|
|
13
15
|
/* eslint-disable no-dupe-class-members */
|
|
14
16
|
|
|
@@ -106,24 +108,28 @@ export class LocalDate {
|
|
|
106
108
|
return (mutate ? items : [...items]).sort((a, b) => a.cmp(b) * mod)
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
static earliestOrUndefined(items:
|
|
111
|
+
static earliestOrUndefined(items: LocalDateConfig[]): LocalDate | undefined {
|
|
110
112
|
return items.length ? LocalDate.earliest(items) : undefined
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
static earliest(items:
|
|
115
|
+
static earliest(items: LocalDateConfig[]): LocalDate {
|
|
114
116
|
_assert(items.length, 'LocalDate.earliest called on empty array')
|
|
115
117
|
|
|
116
|
-
return items
|
|
118
|
+
return items
|
|
119
|
+
.map(i => LocalDate.of(i))
|
|
120
|
+
.reduce((min, item) => (min.isSameOrBefore(item) ? min : item))
|
|
117
121
|
}
|
|
118
122
|
|
|
119
|
-
static latestOrUndefined(items:
|
|
123
|
+
static latestOrUndefined(items: LocalDateConfig[]): LocalDate | undefined {
|
|
120
124
|
return items.length ? LocalDate.latest(items) : undefined
|
|
121
125
|
}
|
|
122
126
|
|
|
123
|
-
static latest(items:
|
|
127
|
+
static latest(items: LocalDateConfig[]): LocalDate {
|
|
124
128
|
_assert(items.length, 'LocalDate.latest called on empty array')
|
|
125
129
|
|
|
126
|
-
return items
|
|
130
|
+
return items
|
|
131
|
+
.map(i => LocalDate.of(i))
|
|
132
|
+
.reduce((max, item) => (max.isSameOrAfter(item) ? max : item))
|
|
127
133
|
}
|
|
128
134
|
|
|
129
135
|
static range(
|
|
@@ -133,6 +139,11 @@ export class LocalDate {
|
|
|
133
139
|
step = 1,
|
|
134
140
|
stepUnit: LocalDateUnit = 'day',
|
|
135
141
|
): LocalDate[] {
|
|
142
|
+
if (stepUnit === 'week') {
|
|
143
|
+
step *= 7
|
|
144
|
+
stepUnit = 'day'
|
|
145
|
+
}
|
|
146
|
+
|
|
136
147
|
const dates: LocalDate[] = []
|
|
137
148
|
const $min = LocalDate.of(min)
|
|
138
149
|
const $max = LocalDate.of(max).startOf(stepUnit)
|
|
@@ -153,11 +164,11 @@ export class LocalDate {
|
|
|
153
164
|
return dates
|
|
154
165
|
}
|
|
155
166
|
|
|
156
|
-
get(unit:
|
|
167
|
+
get(unit: LocalDateUnitStrict): number {
|
|
157
168
|
return unit === 'year' ? this.$year : unit === 'month' ? this.$month : this.$day
|
|
158
169
|
}
|
|
159
170
|
|
|
160
|
-
set(unit:
|
|
171
|
+
set(unit: LocalDateUnitStrict, v: number, mutate = false): LocalDate {
|
|
161
172
|
const t = mutate ? this : this.clone()
|
|
162
173
|
|
|
163
174
|
if (unit === 'year') {
|
|
@@ -257,7 +268,7 @@ export class LocalDate {
|
|
|
257
268
|
return (this.$year - d.$year) * 12 + (this.$month - d.$month)
|
|
258
269
|
}
|
|
259
270
|
|
|
260
|
-
// unit is 'day'
|
|
271
|
+
// unit is 'day' or 'week'
|
|
261
272
|
let days = this.$day - d.$day
|
|
262
273
|
|
|
263
274
|
if (d.$year < this.$year) {
|
|
@@ -280,12 +291,21 @@ export class LocalDate {
|
|
|
280
291
|
}
|
|
281
292
|
}
|
|
282
293
|
|
|
294
|
+
if (unit === 'week') {
|
|
295
|
+
return Math.floor(days / 7)
|
|
296
|
+
}
|
|
297
|
+
|
|
283
298
|
return days
|
|
284
299
|
}
|
|
285
300
|
|
|
286
301
|
add(num: number, unit: LocalDateUnit, mutate = false): LocalDate {
|
|
287
302
|
let { $day, $month, $year } = this
|
|
288
303
|
|
|
304
|
+
if (unit === 'week') {
|
|
305
|
+
num *= 7
|
|
306
|
+
unit = 'day'
|
|
307
|
+
}
|
|
308
|
+
|
|
289
309
|
if (unit === 'day') {
|
|
290
310
|
$day += num
|
|
291
311
|
} else if (unit === 'month') {
|
|
@@ -346,14 +366,14 @@ export class LocalDate {
|
|
|
346
366
|
return this.add(-num, unit, mutate)
|
|
347
367
|
}
|
|
348
368
|
|
|
349
|
-
startOf(unit:
|
|
369
|
+
startOf(unit: LocalDateUnitStrict): LocalDate {
|
|
350
370
|
if (unit === 'day') return this
|
|
351
371
|
if (unit === 'month') return LocalDate.create(this.$year, this.$month, 1)
|
|
352
372
|
// year
|
|
353
373
|
return LocalDate.create(this.$year, 1, 1)
|
|
354
374
|
}
|
|
355
375
|
|
|
356
|
-
endOf(unit:
|
|
376
|
+
endOf(unit: LocalDateUnitStrict): LocalDate {
|
|
357
377
|
if (unit === 'day') return this
|
|
358
378
|
if (unit === 'month')
|
|
359
379
|
return LocalDate.create(
|
|
@@ -400,6 +420,13 @@ export class LocalDate {
|
|
|
400
420
|
return this.toString()
|
|
401
421
|
}
|
|
402
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Returns e.g: `1984-06-21T17:56:21`
|
|
425
|
+
*/
|
|
426
|
+
toISODateTime(): IsoDateTimeString {
|
|
427
|
+
return this.toString() + 'T00:00:00'
|
|
428
|
+
}
|
|
429
|
+
|
|
403
430
|
toString(): IsoDateString {
|
|
404
431
|
return [
|
|
405
432
|
String(this.$year).padStart(4, '0'),
|
|
@@ -428,6 +455,10 @@ export class LocalDate {
|
|
|
428
455
|
toJSON(): IsoDateString {
|
|
429
456
|
return this.toString()
|
|
430
457
|
}
|
|
458
|
+
|
|
459
|
+
format(fmt: LocalDateFormatter): string {
|
|
460
|
+
return fmt(this)
|
|
461
|
+
}
|
|
431
462
|
}
|
|
432
463
|
|
|
433
464
|
/**
|