@naturalcycles/js-lib 14.97.0 → 14.98.1
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/dateInterval.d.ts +8 -7
- package/dist/datetime/dateInterval.js +18 -15
- package/dist/datetime/localDate.d.ts +4 -9
- package/dist/datetime/localDate.js +58 -56
- package/dist/datetime/localTime.d.ts +4 -2
- package/dist/datetime/localTime.js +33 -10
- package/dist/datetime/timeInterval.d.ts +38 -0
- package/dist/datetime/timeInterval.js +91 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/json-schema/jsonSchemaBuilder.d.ts +2 -2
- package/dist/math/math.util.d.ts +4 -0
- package/dist/math/math.util.js +8 -1
- package/dist/math/sma.d.ts +4 -0
- package/dist/math/sma.js +4 -0
- package/dist/types.d.ts +27 -27
- package/dist-esm/datetime/dateInterval.js +18 -15
- package/dist-esm/datetime/localDate.js +58 -56
- package/dist-esm/datetime/localTime.js +33 -10
- package/dist-esm/datetime/timeInterval.js +87 -0
- package/dist-esm/index.js +1 -0
- package/dist-esm/math/math.util.js +6 -0
- package/dist-esm/math/sma.js +4 -0
- package/package.json +1 -1
- package/src/datetime/dateInterval.ts +22 -18
- package/src/datetime/localDate.ts +66 -85
- package/src/datetime/localTime.ts +37 -11
- package/src/datetime/timeInterval.ts +104 -0
- package/src/index.ts +4 -0
- package/src/json-schema/jsonSchemaBuilder.ts +6 -2
- package/src/math/math.util.ts +7 -0
- package/src/math/sma.ts +4 -0
- package/src/types.ts +39 -32
package/dist/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Merge, Promisable } from './typeFest';
|
|
|
5
5
|
* Alternative: Record<string, T | undefined>
|
|
6
6
|
*/
|
|
7
7
|
export interface StringMap<T = string> {
|
|
8
|
-
[k: string]: T | undefined;
|
|
8
|
+
[k: string | number]: T | undefined;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
11
|
* Object to be passed to pProps to resolve all promises into properties.
|
|
@@ -24,14 +24,37 @@ export interface CreatedUpdated {
|
|
|
24
24
|
created: number;
|
|
25
25
|
updated: number;
|
|
26
26
|
}
|
|
27
|
-
export interface CreatedUpdatedId<ID = string> extends CreatedUpdated {
|
|
27
|
+
export interface CreatedUpdatedId<ID extends string | number = string | number> extends CreatedUpdated {
|
|
28
28
|
id: ID;
|
|
29
29
|
}
|
|
30
|
-
export interface ObjectWithId<ID = string> {
|
|
30
|
+
export interface ObjectWithId<ID extends string | number = string | number> {
|
|
31
31
|
id: ID;
|
|
32
32
|
}
|
|
33
|
-
export interface AnyObjectWithId<ID = string> extends AnyObject, ObjectWithId<ID> {
|
|
33
|
+
export interface AnyObjectWithId<ID extends string | number = string | number> extends AnyObject, ObjectWithId<ID> {
|
|
34
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Base interface for any Entity that was saved to DB.
|
|
37
|
+
*/
|
|
38
|
+
export interface SavedDBEntity<ID extends string | number = string> {
|
|
39
|
+
id: ID;
|
|
40
|
+
/**
|
|
41
|
+
* unixTimestamp of when the entity was first created (in the DB).
|
|
42
|
+
*/
|
|
43
|
+
created: UnixTimestampNumber;
|
|
44
|
+
/**
|
|
45
|
+
* unixTimestamp of when the entity was last updated (in the DB).
|
|
46
|
+
*/
|
|
47
|
+
updated: UnixTimestampNumber;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Base interface for any Entity that can be saved to DB.
|
|
51
|
+
* This interface fits when entity was NOT YET saved to DB,
|
|
52
|
+
* hence `id`, `created` and `updated` fields CAN BE undefined (yet).
|
|
53
|
+
* When it's known to be saved - `SavedDBEntity` interface can be used instead.
|
|
54
|
+
*/
|
|
55
|
+
export declare type BaseDBEntity<ID extends string | number = string> = Partial<SavedDBEntity<ID>>;
|
|
56
|
+
export declare type Saved<T extends Partial<ObjectWithId>> = Merge<T, SavedDBEntity<Exclude<T['id'], undefined>>>;
|
|
57
|
+
export declare type Unsaved<T extends ObjectWithId> = Merge<T, BaseDBEntity<T['id']>>;
|
|
35
58
|
/**
|
|
36
59
|
* Convenience type shorthand.
|
|
37
60
|
* Because `Function` type is discouraged by eslint.
|
|
@@ -136,29 +159,6 @@ export declare type UnixTimestamp = number;
|
|
|
136
159
|
* Same as `number`, but with semantic meaning that it's an Integer.
|
|
137
160
|
*/
|
|
138
161
|
export declare type Integer = number;
|
|
139
|
-
/**
|
|
140
|
-
* Base interface for any Entity that was saved to DB.
|
|
141
|
-
*/
|
|
142
|
-
export interface SavedDBEntity<ID = string> {
|
|
143
|
-
id: ID;
|
|
144
|
-
/**
|
|
145
|
-
* unixTimestamp of when the entity was first created (in the DB).
|
|
146
|
-
*/
|
|
147
|
-
created: UnixTimestampNumber;
|
|
148
|
-
/**
|
|
149
|
-
* unixTimestamp of when the entity was last updated (in the DB).
|
|
150
|
-
*/
|
|
151
|
-
updated: UnixTimestampNumber;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Base interface for any Entity that can be saved to DB.
|
|
155
|
-
* This interface fits when entity was NOT YET saved to DB,
|
|
156
|
-
* hence `id`, `created` and `updated` fields CAN BE undefined (yet).
|
|
157
|
-
* When it's known to be saved - `SavedDBEntity` interface can be used instead.
|
|
158
|
-
*/
|
|
159
|
-
export declare type BaseDBEntity<ID = string> = Partial<SavedDBEntity<ID>>;
|
|
160
|
-
export declare type Saved<E, ID = string> = Merge<E, SavedDBEntity<ID>>;
|
|
161
|
-
export declare type Unsaved<E, ID = string> = Merge<E, BaseDBEntity<ID>>;
|
|
162
162
|
/**
|
|
163
163
|
* Named type for JSON.parse / JSON.stringify second argument
|
|
164
164
|
*/
|
|
@@ -27,14 +27,16 @@ export class DateInterval {
|
|
|
27
27
|
isSame(d) {
|
|
28
28
|
return this.cmp(d) === 0;
|
|
29
29
|
}
|
|
30
|
-
isBefore(d) {
|
|
31
|
-
|
|
30
|
+
isBefore(d, inclusive = false) {
|
|
31
|
+
const r = this.cmp(d);
|
|
32
|
+
return r === -1 || (r === 0 && inclusive);
|
|
32
33
|
}
|
|
33
34
|
isSameOrBefore(d) {
|
|
34
35
|
return this.cmp(d) <= 0;
|
|
35
36
|
}
|
|
36
|
-
isAfter(d) {
|
|
37
|
-
|
|
37
|
+
isAfter(d, inclusive = false) {
|
|
38
|
+
const r = this.cmp(d);
|
|
39
|
+
return r === 1 || (r === 0 && inclusive);
|
|
38
40
|
}
|
|
39
41
|
isSameOrAfter(d) {
|
|
40
42
|
return this.cmp(d) >= 0;
|
|
@@ -42,9 +44,14 @@ export class DateInterval {
|
|
|
42
44
|
/**
|
|
43
45
|
* Ranges of DateInterval (start, end) are INCLUSIVE.
|
|
44
46
|
*/
|
|
45
|
-
includes(d) {
|
|
47
|
+
includes(d, incl = '[]') {
|
|
46
48
|
d = LocalDate.of(d);
|
|
47
|
-
return d.
|
|
49
|
+
return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']');
|
|
50
|
+
}
|
|
51
|
+
intersects(int, inclusive = true) {
|
|
52
|
+
const $int = DateInterval.parse(int);
|
|
53
|
+
const incl = inclusive ? '[]' : '()';
|
|
54
|
+
return this.includes($int.start, incl) || this.includes($int.end, incl);
|
|
48
55
|
}
|
|
49
56
|
/**
|
|
50
57
|
* DateIntervals compare by start date.
|
|
@@ -54,18 +61,14 @@ export class DateInterval {
|
|
|
54
61
|
d = DateInterval.parse(d);
|
|
55
62
|
return this.start.cmp(d.start) || this.end.cmp(d.end);
|
|
56
63
|
}
|
|
64
|
+
getDays(incl = '[]') {
|
|
65
|
+
return LocalDate.range(this.start, this.end, incl, 1, 'day');
|
|
66
|
+
}
|
|
57
67
|
/**
|
|
58
68
|
* Returns an array of LocalDates that are included in the interval.
|
|
59
|
-
* Ranges are INCLUSIVE.
|
|
60
69
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
let current = this.start;
|
|
64
|
-
do {
|
|
65
|
-
days.push(current);
|
|
66
|
-
current = current.add(1, 'day');
|
|
67
|
-
} while (current.isSameOrBefore(this.end));
|
|
68
|
-
return days;
|
|
70
|
+
range(incl = '[]', step = 1, stepUnit = 'day') {
|
|
71
|
+
return LocalDate.range(this.start, this.end, incl, step, stepUnit);
|
|
69
72
|
}
|
|
70
73
|
toString() {
|
|
71
74
|
return [this.start, this.end].join('/');
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { _assert } from '../error/assert';
|
|
2
|
-
import { Sequence } from '../seq/seq';
|
|
3
|
-
import { END } from '../types';
|
|
4
2
|
import { LocalTime } from './localTime';
|
|
5
|
-
const
|
|
3
|
+
const MDAYS = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
|
4
|
+
const DATE_REGEX = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
|
|
6
5
|
/* eslint-disable no-dupe-class-members */
|
|
7
6
|
/**
|
|
8
7
|
* @experimental
|
|
@@ -48,8 +47,13 @@ export class LocalDate {
|
|
|
48
47
|
return null;
|
|
49
48
|
if (d instanceof LocalDate)
|
|
50
49
|
return d;
|
|
51
|
-
//
|
|
52
|
-
const
|
|
50
|
+
// const [year, month, day] = d.slice(0, 10).split('-').map(Number)
|
|
51
|
+
const matches = DATE_REGEX.exec(d.slice(0, 10));
|
|
52
|
+
if (!matches)
|
|
53
|
+
return null;
|
|
54
|
+
const year = Number(matches[1]);
|
|
55
|
+
const month = Number(matches[2]);
|
|
56
|
+
const day = Number(matches[3]);
|
|
53
57
|
if (!year ||
|
|
54
58
|
!month ||
|
|
55
59
|
month < 1 ||
|
|
@@ -61,6 +65,10 @@ export class LocalDate {
|
|
|
61
65
|
}
|
|
62
66
|
return new LocalDate(year, month, day);
|
|
63
67
|
}
|
|
68
|
+
// Can use just .toString()
|
|
69
|
+
// static parseToString(d: LocalDateConfig): IsoDateString {
|
|
70
|
+
// return typeof d === 'string' ? d : d.toString()
|
|
71
|
+
// }
|
|
64
72
|
static isValid(iso) {
|
|
65
73
|
return this.parseOrNull(iso) !== null;
|
|
66
74
|
}
|
|
@@ -88,32 +96,23 @@ export class LocalDate {
|
|
|
88
96
|
_assert(items.length, 'LocalDate.latest called on empty array');
|
|
89
97
|
return items.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
|
|
90
98
|
}
|
|
91
|
-
static range(
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
const max = LocalDate.of(
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
static range(min, max, incl = '[)', step = 1, stepUnit = 'day') {
|
|
100
|
+
const dates = [];
|
|
101
|
+
const $min = LocalDate.of(min);
|
|
102
|
+
const $max = LocalDate.of(max).startOf(stepUnit);
|
|
103
|
+
let current = $min.startOf(stepUnit);
|
|
104
|
+
if (current.isAfter($min, incl[0] === '[')) {
|
|
105
|
+
// ok
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
current.add(1, stepUnit, true);
|
|
109
|
+
}
|
|
110
|
+
const incl2 = incl[1] === ']';
|
|
111
|
+
while (current.isBefore($max, incl2)) {
|
|
112
|
+
dates.push(current);
|
|
97
113
|
current = current.add(step, stepUnit);
|
|
98
|
-
}
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
static rangeSeq(minIncl, maxExcl, step = 1, stepUnit = 'day') {
|
|
102
|
-
const min = LocalDate.of(minIncl).startOf(stepUnit);
|
|
103
|
-
const max = LocalDate.of(maxExcl).startOf(stepUnit);
|
|
104
|
-
return Sequence.create(min, d => {
|
|
105
|
-
const next = d.add(step, stepUnit);
|
|
106
|
-
return next.isAfter(max) ? END : next;
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
static rangeString(minIncl, maxExcl, step = 1, stepUnit = 'day') {
|
|
110
|
-
return LocalDate.range(minIncl, maxExcl, step, stepUnit).map(ld => ld.toString());
|
|
111
|
-
}
|
|
112
|
-
static rangeIncl(minIncl, maxIncl, step = 1, stepUnit = 'day') {
|
|
113
|
-
return LocalDate.range(minIncl, LocalDate.of(maxIncl).add(1, stepUnit), step, stepUnit);
|
|
114
|
-
}
|
|
115
|
-
static rangeInclString(minIncl, maxIncl, step = 1, stepUnit = 'day') {
|
|
116
|
-
return LocalDate.range(minIncl, LocalDate.of(maxIncl).add(1, stepUnit), step, stepUnit).map(ld => ld.toString());
|
|
114
|
+
}
|
|
115
|
+
return dates;
|
|
117
116
|
}
|
|
118
117
|
get(unit) {
|
|
119
118
|
return unit === 'year' ? this.$year : unit === 'month' ? this.$month : this.$day;
|
|
@@ -144,14 +143,16 @@ export class LocalDate {
|
|
|
144
143
|
d = LocalDate.of(d);
|
|
145
144
|
return this.$day === d.$day && this.$month === d.$month && this.$year === d.$year;
|
|
146
145
|
}
|
|
147
|
-
isBefore(d) {
|
|
148
|
-
|
|
146
|
+
isBefore(d, inclusive = false) {
|
|
147
|
+
const r = this.cmp(d);
|
|
148
|
+
return r === -1 || (r === 0 && inclusive);
|
|
149
149
|
}
|
|
150
150
|
isSameOrBefore(d) {
|
|
151
151
|
return this.cmp(d) <= 0;
|
|
152
152
|
}
|
|
153
|
-
isAfter(d) {
|
|
154
|
-
|
|
153
|
+
isAfter(d, inclusive = false) {
|
|
154
|
+
const r = this.cmp(d);
|
|
155
|
+
return r === 1 || (r === 0 && inclusive);
|
|
155
156
|
}
|
|
156
157
|
isSameOrAfter(d) {
|
|
157
158
|
return this.cmp(d) >= 0;
|
|
@@ -241,24 +242,29 @@ export class LocalDate {
|
|
|
241
242
|
$year += num;
|
|
242
243
|
}
|
|
243
244
|
// check day overflow
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
245
|
+
if (unit === 'day') {
|
|
246
|
+
if ($day < 1) {
|
|
247
|
+
while ($day < 1) {
|
|
248
|
+
$month -= 1;
|
|
249
|
+
if ($month < 1) {
|
|
250
|
+
$year -= 1;
|
|
251
|
+
$month += 12;
|
|
252
|
+
}
|
|
253
|
+
$day += LocalDate.getMonthLength($year, $month);
|
|
254
|
+
}
|
|
251
255
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
256
|
+
else {
|
|
257
|
+
let monLen = LocalDate.getMonthLength($year, $month);
|
|
258
|
+
while ($day > monLen) {
|
|
259
|
+
$day -= monLen;
|
|
260
|
+
$month += 1;
|
|
261
|
+
if ($month > 12) {
|
|
262
|
+
$year += 1;
|
|
263
|
+
$month -= 12;
|
|
264
|
+
}
|
|
265
|
+
monLen = LocalDate.getMonthLength($year, $month);
|
|
266
|
+
}
|
|
260
267
|
}
|
|
261
|
-
monLen = LocalDate.getMonthLength($year, $month);
|
|
262
268
|
}
|
|
263
269
|
// check month overflow
|
|
264
270
|
while ($month > 12) {
|
|
@@ -302,14 +308,10 @@ export class LocalDate {
|
|
|
302
308
|
static getMonthLength(year, month) {
|
|
303
309
|
if (month === 2)
|
|
304
310
|
return this.isLeapYear(year) ? 29 : 28;
|
|
305
|
-
return
|
|
311
|
+
return MDAYS[month];
|
|
306
312
|
}
|
|
307
313
|
static isLeapYear(year) {
|
|
308
|
-
|
|
309
|
-
return false;
|
|
310
|
-
if (year % 100 !== 0)
|
|
311
|
-
return true;
|
|
312
|
-
return year % 400 === 0;
|
|
314
|
+
return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
|
|
313
315
|
}
|
|
314
316
|
clone() {
|
|
315
317
|
return new LocalDate(this.$year, this.$month, this.$day);
|
|
@@ -45,7 +45,7 @@ export class LocalTime {
|
|
|
45
45
|
date = new Date(d * 1000);
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
date = new Date(d);
|
|
48
|
+
date = new Date(d.slice(0, 19));
|
|
49
49
|
}
|
|
50
50
|
// validation
|
|
51
51
|
if (isNaN(date.getDate())) {
|
|
@@ -57,6 +57,28 @@ export class LocalTime {
|
|
|
57
57
|
// }
|
|
58
58
|
return new LocalTime(date, false);
|
|
59
59
|
}
|
|
60
|
+
static parseToDate(d) {
|
|
61
|
+
if (d instanceof LocalTime)
|
|
62
|
+
return d.$date;
|
|
63
|
+
if (d instanceof Date)
|
|
64
|
+
return d;
|
|
65
|
+
const date = typeof d === 'number' ? new Date(d * 1000) : new Date(d);
|
|
66
|
+
if (isNaN(date.getDate())) {
|
|
67
|
+
throw new TypeError(`Cannot parse "${d}" to Date`);
|
|
68
|
+
}
|
|
69
|
+
return date;
|
|
70
|
+
}
|
|
71
|
+
static parseToUnixTimestamp(d) {
|
|
72
|
+
if (typeof d === 'number')
|
|
73
|
+
return d;
|
|
74
|
+
if (d instanceof LocalTime)
|
|
75
|
+
return d.unix();
|
|
76
|
+
const date = d instanceof Date ? d : new Date(d);
|
|
77
|
+
if (isNaN(date.getDate())) {
|
|
78
|
+
throw new TypeError(`Cannot parse "${d}" to UnixTimestamp`);
|
|
79
|
+
}
|
|
80
|
+
return date.valueOf() / 1000;
|
|
81
|
+
}
|
|
60
82
|
static isValid(d) {
|
|
61
83
|
return this.parseOrNull(d) !== null;
|
|
62
84
|
}
|
|
@@ -161,7 +183,7 @@ export class LocalTime {
|
|
|
161
183
|
return Math.abs(this.diff(other, unit));
|
|
162
184
|
}
|
|
163
185
|
diff(other, unit) {
|
|
164
|
-
const date2 = LocalTime.
|
|
186
|
+
const date2 = LocalTime.parseToDate(other);
|
|
165
187
|
if (unit === 'year') {
|
|
166
188
|
return this.$date.getFullYear() - date2.getFullYear();
|
|
167
189
|
}
|
|
@@ -238,14 +260,16 @@ export class LocalTime {
|
|
|
238
260
|
isSame(d) {
|
|
239
261
|
return this.cmp(d) === 0;
|
|
240
262
|
}
|
|
241
|
-
isBefore(d) {
|
|
242
|
-
|
|
263
|
+
isBefore(d, inclusive = false) {
|
|
264
|
+
const r = this.cmp(d);
|
|
265
|
+
return r === -1 || (r === 0 && inclusive);
|
|
243
266
|
}
|
|
244
267
|
isSameOrBefore(d) {
|
|
245
268
|
return this.cmp(d) <= 0;
|
|
246
269
|
}
|
|
247
|
-
isAfter(d) {
|
|
248
|
-
|
|
270
|
+
isAfter(d, inclusive = false) {
|
|
271
|
+
const r = this.cmp(d);
|
|
272
|
+
return r === 1 || (r === 0 && inclusive);
|
|
249
273
|
}
|
|
250
274
|
isSameOrAfter(d) {
|
|
251
275
|
return this.cmp(d) >= 0;
|
|
@@ -266,7 +290,7 @@ export class LocalTime {
|
|
|
266
290
|
*/
|
|
267
291
|
cmp(d) {
|
|
268
292
|
const t1 = this.$date.valueOf();
|
|
269
|
-
const t2 = LocalTime.
|
|
293
|
+
const t2 = LocalTime.parseToDate(d).valueOf();
|
|
270
294
|
if (t1 === t2)
|
|
271
295
|
return 0;
|
|
272
296
|
return t1 < t2 ? -1 : 1;
|
|
@@ -292,8 +316,8 @@ export class LocalTime {
|
|
|
292
316
|
second: this.$date.getSeconds(),
|
|
293
317
|
};
|
|
294
318
|
}
|
|
295
|
-
fromNow(now =
|
|
296
|
-
const msDiff = LocalTime.
|
|
319
|
+
fromNow(now = new Date()) {
|
|
320
|
+
const msDiff = LocalTime.parseToDate(now).valueOf() - this.$date.valueOf();
|
|
297
321
|
if (msDiff === 0)
|
|
298
322
|
return 'now';
|
|
299
323
|
if (msDiff >= 0) {
|
|
@@ -403,4 +427,3 @@ export class LocalTime {
|
|
|
403
427
|
export function localTime(d) {
|
|
404
428
|
return d ? LocalTime.of(d) : LocalTime.now();
|
|
405
429
|
}
|
|
406
|
-
// todo: range
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { LocalTime } from './localTime';
|
|
2
|
+
/**
|
|
3
|
+
* Class that supports an "interval of time" between 2 timestamps - start and end.
|
|
4
|
+
* Example: `1649267185/1649267187`.
|
|
5
|
+
*
|
|
6
|
+
* @experimental
|
|
7
|
+
*/
|
|
8
|
+
export class TimeInterval {
|
|
9
|
+
constructor($start, $end) {
|
|
10
|
+
this.$start = $start;
|
|
11
|
+
this.$end = $end;
|
|
12
|
+
}
|
|
13
|
+
static of(start, end) {
|
|
14
|
+
return new TimeInterval(LocalTime.parseToUnixTimestamp(start), LocalTime.parseToUnixTimestamp(end));
|
|
15
|
+
}
|
|
16
|
+
get start() {
|
|
17
|
+
return this.$start;
|
|
18
|
+
}
|
|
19
|
+
get end() {
|
|
20
|
+
return this.$end;
|
|
21
|
+
}
|
|
22
|
+
get startTime() {
|
|
23
|
+
return LocalTime.of(this.$start);
|
|
24
|
+
}
|
|
25
|
+
get endTime() {
|
|
26
|
+
return LocalTime.of(this.$end);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parses string like `1649267185/1649267187` into a TimeInterval.
|
|
30
|
+
*/
|
|
31
|
+
static parse(d) {
|
|
32
|
+
if (d instanceof TimeInterval)
|
|
33
|
+
return d;
|
|
34
|
+
const [start, end] = d.split('/').map(Number);
|
|
35
|
+
if (!end || !start) {
|
|
36
|
+
throw new Error(`Cannot parse "${d}" into TimeInterval`);
|
|
37
|
+
}
|
|
38
|
+
return new TimeInterval(start, end);
|
|
39
|
+
}
|
|
40
|
+
isSame(d) {
|
|
41
|
+
return this.cmp(d) === 0;
|
|
42
|
+
}
|
|
43
|
+
isBefore(d, inclusive = false) {
|
|
44
|
+
const r = this.cmp(d);
|
|
45
|
+
return r === -1 || (r === 0 && inclusive);
|
|
46
|
+
}
|
|
47
|
+
isSameOrBefore(d) {
|
|
48
|
+
return this.cmp(d) <= 0;
|
|
49
|
+
}
|
|
50
|
+
isAfter(d, inclusive = false) {
|
|
51
|
+
const r = this.cmp(d);
|
|
52
|
+
return r === 1 || (r === 0 && inclusive);
|
|
53
|
+
}
|
|
54
|
+
isSameOrAfter(d) {
|
|
55
|
+
return this.cmp(d) >= 0;
|
|
56
|
+
}
|
|
57
|
+
includes(d, incl = '[)') {
|
|
58
|
+
d = LocalTime.parseToUnixTimestamp(d);
|
|
59
|
+
if (d < this.$start || (d === this.$start && incl[0] === '('))
|
|
60
|
+
return false;
|
|
61
|
+
if (d > this.$end || (d === this.$end && incl[1] === ')'))
|
|
62
|
+
return false;
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* TimeIntervals compare by start date.
|
|
67
|
+
* If it's the same - then by end date.
|
|
68
|
+
*/
|
|
69
|
+
cmp(d) {
|
|
70
|
+
d = TimeInterval.parse(d);
|
|
71
|
+
if (this.$start > d.$start)
|
|
72
|
+
return 1;
|
|
73
|
+
if (this.$start < d.$start)
|
|
74
|
+
return -1;
|
|
75
|
+
if (this.$end > d.$end)
|
|
76
|
+
return 1;
|
|
77
|
+
if (this.$end < d.$end)
|
|
78
|
+
return -1;
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
toString() {
|
|
82
|
+
return [this.$start, this.$end].join('/');
|
|
83
|
+
}
|
|
84
|
+
toJSON() {
|
|
85
|
+
return this.toString();
|
|
86
|
+
}
|
|
87
|
+
}
|
package/dist-esm/index.js
CHANGED
|
@@ -59,4 +59,5 @@ export * from './string/leven';
|
|
|
59
59
|
export * from './datetime/localDate';
|
|
60
60
|
export * from './datetime/localTime';
|
|
61
61
|
export * from './datetime/dateInterval';
|
|
62
|
+
export * from './datetime/timeInterval';
|
|
62
63
|
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, };
|
|
@@ -10,6 +10,12 @@ import { _sortNumbers } from '../number/number.util';
|
|
|
10
10
|
export function _average(values) {
|
|
11
11
|
return values.reduce((a, b) => a + b) / values.length;
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Same as _average, but safely returns null if input array is empty or nullish.
|
|
15
|
+
*/
|
|
16
|
+
export function _averageOrNull(values) {
|
|
17
|
+
return (values === null || values === void 0 ? void 0 : values.length) ? values.reduce((a, b) => a + b) / values.length : null;
|
|
18
|
+
}
|
|
13
19
|
/**
|
|
14
20
|
* valuesArray and weightsArray length is expected to be the same.
|
|
15
21
|
*/
|
package/dist-esm/math/sma.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { LocalDate, LocalDateConfig } from './localDate'
|
|
1
|
+
import { Inclusiveness, LocalDate, LocalDateConfig, LocalDateUnit } from './localDate'
|
|
2
2
|
|
|
3
|
-
export type DateIntervalConfig = DateInterval |
|
|
3
|
+
export type DateIntervalConfig = DateInterval | DateIntervalString
|
|
4
4
|
export type DateIntervalString = string
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -34,16 +34,18 @@ export class DateInterval {
|
|
|
34
34
|
return this.cmp(d) === 0
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
isBefore(d: DateIntervalConfig): boolean {
|
|
38
|
-
|
|
37
|
+
isBefore(d: DateIntervalConfig, inclusive = false): boolean {
|
|
38
|
+
const r = this.cmp(d)
|
|
39
|
+
return r === -1 || (r === 0 && inclusive)
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
isSameOrBefore(d: DateIntervalConfig): boolean {
|
|
42
43
|
return this.cmp(d) <= 0
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
isAfter(d: DateIntervalConfig): boolean {
|
|
46
|
-
|
|
46
|
+
isAfter(d: DateIntervalConfig, inclusive = false): boolean {
|
|
47
|
+
const r = this.cmp(d)
|
|
48
|
+
return r === 1 || (r === 0 && inclusive)
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
isSameOrAfter(d: DateIntervalConfig): boolean {
|
|
@@ -53,9 +55,15 @@ export class DateInterval {
|
|
|
53
55
|
/**
|
|
54
56
|
* Ranges of DateInterval (start, end) are INCLUSIVE.
|
|
55
57
|
*/
|
|
56
|
-
includes(d: LocalDateConfig): boolean {
|
|
58
|
+
includes(d: LocalDateConfig, incl: Inclusiveness = '[]'): boolean {
|
|
57
59
|
d = LocalDate.of(d)
|
|
58
|
-
return d.
|
|
60
|
+
return d.isAfter(this.start, incl[0] === '[') && d.isBefore(this.end, incl[1] === ']')
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
intersects(int: DateIntervalConfig, inclusive = true): boolean {
|
|
64
|
+
const $int = DateInterval.parse(int)
|
|
65
|
+
const incl = inclusive ? '[]' : '()'
|
|
66
|
+
return this.includes($int.start, incl) || this.includes($int.end, incl)
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
/**
|
|
@@ -67,19 +75,15 @@ export class DateInterval {
|
|
|
67
75
|
return this.start.cmp(d.start) || this.end.cmp(d.end)
|
|
68
76
|
}
|
|
69
77
|
|
|
78
|
+
getDays(incl: Inclusiveness = '[]'): LocalDate[] {
|
|
79
|
+
return LocalDate.range(this.start, this.end, incl, 1, 'day')
|
|
80
|
+
}
|
|
81
|
+
|
|
70
82
|
/**
|
|
71
83
|
* Returns an array of LocalDates that are included in the interval.
|
|
72
|
-
* Ranges are INCLUSIVE.
|
|
73
84
|
*/
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
let current = this.start
|
|
77
|
-
do {
|
|
78
|
-
days.push(current)
|
|
79
|
-
current = current.add(1, 'day')
|
|
80
|
-
} while (current.isSameOrBefore(this.end))
|
|
81
|
-
|
|
82
|
-
return days
|
|
85
|
+
range(incl: Inclusiveness = '[]', step = 1, stepUnit: LocalDateUnit = 'day'): LocalDate[] {
|
|
86
|
+
return LocalDate.range(this.start, this.end, incl, step, stepUnit)
|
|
83
87
|
}
|
|
84
88
|
|
|
85
89
|
toString(): DateIntervalString {
|