@naturalcycles/js-lib 14.98.3 → 14.99.2

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.
@@ -1,17 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.localTime = exports.LocalTime = void 0;
3
+ exports.localTime = exports.LocalTime = exports.ISODayOfWeek = void 0;
4
4
  const assert_1 = require("../error/assert");
5
5
  const time_util_1 = require("../time/time.util");
6
6
  const localDate_1 = require("./localDate");
7
+ var ISODayOfWeek;
8
+ (function (ISODayOfWeek) {
9
+ ISODayOfWeek[ISODayOfWeek["MONDAY"] = 1] = "MONDAY";
10
+ ISODayOfWeek[ISODayOfWeek["TUESDAY"] = 2] = "TUESDAY";
11
+ ISODayOfWeek[ISODayOfWeek["WEDNESDAY"] = 3] = "WEDNESDAY";
12
+ ISODayOfWeek[ISODayOfWeek["THURSDAY"] = 4] = "THURSDAY";
13
+ ISODayOfWeek[ISODayOfWeek["FRIDAY"] = 5] = "FRIDAY";
14
+ ISODayOfWeek[ISODayOfWeek["SATURDAY"] = 6] = "SATURDAY";
15
+ ISODayOfWeek[ISODayOfWeek["SUNDAY"] = 7] = "SUNDAY";
16
+ })(ISODayOfWeek = exports.ISODayOfWeek || (exports.ISODayOfWeek = {}));
17
+ const weekStartsOn = 1; // mon, as per ISO
18
+ const MILLISECONDS_IN_WEEK = 604800000;
19
+ const SECONDS_IN_DAY = 86400;
20
+ // const MILLISECONDS_IN_DAY = 86400000
21
+ // const MILLISECONDS_IN_MINUTE = 60000
22
+ const VALID_DAYS_OF_WEEK = new Set([1, 2, 3, 4, 5, 6, 7]);
7
23
  /* eslint-disable no-dupe-class-members */
8
24
  /**
9
25
  * @experimental
10
26
  */
11
27
  class LocalTime {
12
- constructor($date, utcMode) {
28
+ constructor($date) {
13
29
  this.$date = $date;
14
- this.utcMode = utcMode;
15
30
  }
16
31
  /**
17
32
  * Parses input String into LocalDate.
@@ -24,14 +39,6 @@ class LocalTime {
24
39
  }
25
40
  return t;
26
41
  }
27
- utc() {
28
- this.utcMode = true;
29
- return this;
30
- }
31
- local() {
32
- this.utcMode = false;
33
- return this;
34
- }
35
42
  /**
36
43
  * Returns null if invalid
37
44
  */
@@ -58,7 +65,7 @@ class LocalTime {
58
65
  // if (utc) {
59
66
  // date.setMinutes(date.getMinutes() + date.getTimezoneOffset())
60
67
  // }
61
- return new LocalTime(date, false);
68
+ return new LocalTime(date);
62
69
  }
63
70
  static parseToDate(d) {
64
71
  if (d instanceof LocalTime)
@@ -86,52 +93,56 @@ class LocalTime {
86
93
  return this.parseOrNull(d) !== null;
87
94
  }
88
95
  static now() {
89
- return new LocalTime(new Date(), false);
96
+ return new LocalTime(new Date());
90
97
  }
91
98
  static fromComponents(c) {
92
- return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second), false);
99
+ return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second));
93
100
  }
94
101
  get(unit) {
95
102
  if (unit === 'year') {
96
- return this.utcMode ? this.$date.getUTCFullYear() : this.$date.getFullYear();
103
+ return this.$date.getFullYear();
97
104
  }
98
105
  if (unit === 'month') {
99
- return (this.utcMode ? this.$date.getUTCMonth() : this.$date.getMonth()) + 1;
106
+ return this.$date.getMonth() + 1;
100
107
  }
101
108
  if (unit === 'day') {
102
- return this.utcMode ? this.$date.getUTCDate() : this.$date.getDate();
109
+ return this.$date.getDate();
103
110
  }
104
111
  if (unit === 'hour') {
105
- return this.utcMode ? this.$date.getUTCHours() : this.$date.getHours();
112
+ return this.$date.getHours();
106
113
  }
107
114
  if (unit === 'minute') {
108
- return this.utcMode ? this.$date.getUTCMinutes() : this.$date.getMinutes();
115
+ return this.$date.getMinutes();
116
+ }
117
+ if (unit === 'week') {
118
+ return getWeek(this.$date);
109
119
  }
110
120
  // second
111
- return this.utcMode ? this.$date.getUTCSeconds() : this.$date.getSeconds();
121
+ return this.$date.getSeconds();
112
122
  }
113
123
  set(unit, v, mutate = false) {
114
124
  const t = mutate ? this : this.clone();
115
- /* eslint-disable @typescript-eslint/no-unused-expressions */
116
125
  if (unit === 'year') {
117
- this.utcMode ? t.$date.setUTCFullYear(v) : t.$date.setFullYear(v);
126
+ t.$date.setFullYear(v);
118
127
  }
119
128
  else if (unit === 'month') {
120
- this.utcMode ? t.$date.setUTCMonth(v - 1) : t.$date.setMonth(v - 1);
129
+ t.$date.setMonth(v - 1);
121
130
  }
122
131
  else if (unit === 'day') {
123
- this.utcMode ? t.$date.setUTCDate(v) : t.$date.setDate(v);
132
+ t.$date.setDate(v);
124
133
  }
125
134
  else if (unit === 'hour') {
126
- this.utcMode ? t.$date.setUTCHours(v) : t.$date.setHours(v);
135
+ t.$date.setHours(v);
127
136
  }
128
137
  else if (unit === 'minute') {
129
- this.utcMode ? t.$date.setUTCMinutes(v) : t.$date.setMinutes(v);
138
+ t.$date.setMinutes(v);
130
139
  }
131
140
  else if (unit === 'second') {
132
- this.utcMode ? t.$date.setUTCSeconds(v) : t.$date.setSeconds(v);
141
+ t.$date.setSeconds(v);
142
+ }
143
+ else if (unit === 'week') {
144
+ setWeek(t.$date, v, true);
133
145
  }
134
- /* eslint-enable @typescript-eslint/no-unused-expressions */
135
146
  return t;
136
147
  }
137
148
  year(v) {
@@ -140,9 +151,21 @@ class LocalTime {
140
151
  month(v) {
141
152
  return v === undefined ? this.get('month') : this.set('month', v);
142
153
  }
154
+ week(v) {
155
+ return v === undefined ? getWeek(this.$date) : this.set('week', v);
156
+ }
143
157
  day(v) {
144
158
  return v === undefined ? this.get('day') : this.set('day', v);
145
159
  }
160
+ dayOfWeek(v) {
161
+ const dow = (this.$date.getDay() || 7);
162
+ if (v === undefined) {
163
+ return dow;
164
+ }
165
+ if (!VALID_DAYS_OF_WEEK.has(v))
166
+ throw new Error(`Invalid dayOfWeek: ${v}`);
167
+ return this.add(v - dow, 'day');
168
+ }
146
169
  hour(v) {
147
170
  return v === undefined ? this.get('hour') : this.set('hour', v);
148
171
  }
@@ -154,29 +177,31 @@ class LocalTime {
154
177
  }
155
178
  setComponents(c, mutate = false) {
156
179
  const d = mutate ? this.$date : new Date(this.$date);
157
- /* eslint-disable @typescript-eslint/no-unused-expressions */
158
180
  if (c.year) {
159
- this.utcMode ? d.setUTCFullYear(c.year) : d.setFullYear(c.year);
181
+ d.setFullYear(c.year);
160
182
  }
161
183
  if (c.month) {
162
- this.utcMode ? d.setUTCMonth(c.month - 1) : d.setMonth(c.month - 1);
184
+ d.setMonth(c.month - 1);
163
185
  }
164
186
  if (c.day) {
165
- this.utcMode ? d.setUTCDate(c.day) : d.setDate(c.day);
187
+ d.setDate(c.day);
166
188
  }
167
189
  if (c.hour !== undefined) {
168
- this.utcMode ? d.setUTCHours(c.hour) : d.setHours(c.hour);
190
+ d.setHours(c.hour);
169
191
  }
170
192
  if (c.minute !== undefined) {
171
- this.utcMode ? d.setUTCMinutes(c.minute) : d.setMinutes(c.minute);
193
+ d.setMinutes(c.minute);
172
194
  }
173
195
  if (c.second !== undefined) {
174
- this.utcMode ? d.setUTCSeconds(c.second) : d.setSeconds(c.second);
196
+ d.setSeconds(c.second);
175
197
  }
176
- /* eslint-enable @typescript-eslint/no-unused-expressions */
177
- return mutate ? this : new LocalTime(d, this.utcMode);
198
+ return mutate ? this : new LocalTime(d);
178
199
  }
179
200
  add(num, unit, mutate = false) {
201
+ if (unit === 'week') {
202
+ num *= 7;
203
+ unit = 'day';
204
+ }
180
205
  return this.set(unit, this.get(unit) + num, mutate);
181
206
  }
182
207
  subtract(num, unit, mutate = false) {
@@ -187,21 +212,43 @@ class LocalTime {
187
212
  }
188
213
  diff(other, unit) {
189
214
  const date2 = LocalTime.parseToDate(other);
190
- if (unit === 'year') {
191
- return this.$date.getFullYear() - date2.getFullYear();
192
- }
193
- if (unit === 'month') {
194
- return ((this.$date.getFullYear() - date2.getFullYear()) * 12 +
195
- this.$date.getMonth() -
196
- date2.getMonth());
197
- }
198
215
  const secDiff = (this.$date.valueOf() - date2.valueOf()) / 1000;
216
+ if (!secDiff)
217
+ 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
+ }
199
243
  let r;
200
244
  if (unit === 'day') {
201
- r = secDiff / (24 * 60 * 60);
245
+ r = secDiff / SECONDS_IN_DAY;
246
+ }
247
+ else if (unit === 'week') {
248
+ r = secDiff / (7 * 24 * 60 * 60);
202
249
  }
203
250
  else if (unit === 'hour') {
204
- r = secDiff / (60 * 60);
251
+ r = secDiff / 3600;
205
252
  }
206
253
  else if (unit === 'minute') {
207
254
  r = secDiff / 60;
@@ -210,32 +257,62 @@ class LocalTime {
210
257
  // unit === 'second'
211
258
  r = secDiff;
212
259
  }
213
- r = r < 0 ? -Math.floor(-r) : Math.floor(r);
214
- if (Object.is(r, -0))
215
- return 0;
216
- return r;
260
+ // `|| 0` is to avoid returning -0
261
+ return Math.trunc(r) || 0;
217
262
  }
218
263
  startOf(unit, mutate = false) {
219
264
  if (unit === 'second')
220
265
  return this;
221
266
  const d = mutate ? this.$date : new Date(this.$date);
222
- d.setMilliseconds(0);
223
- d.setSeconds(0);
224
- /* eslint-disable @typescript-eslint/no-unused-expressions */
267
+ d.setSeconds(0, 0);
225
268
  if (unit !== 'minute') {
226
- this.utcMode ? d.setUTCMinutes(0) : d.setMinutes(0);
269
+ d.setMinutes(0);
227
270
  if (unit !== 'hour') {
228
- this.utcMode ? d.setUTCHours(0) : d.setHours(0);
271
+ d.setHours(0);
229
272
  if (unit !== 'day') {
230
- this.utcMode ? d.setUTCDate(0) : d.setDate(0);
231
- if (unit !== 'month') {
232
- this.utcMode ? d.setUTCMonth(0) : d.setMonth(0);
273
+ // year, month or week
274
+ if (unit === 'year') {
275
+ d.setMonth(0);
276
+ d.setDate(1);
277
+ }
278
+ else if (unit === 'month') {
279
+ d.setDate(1);
280
+ }
281
+ else {
282
+ // week
283
+ startOfWeek(d, true);
233
284
  }
234
285
  }
235
286
  }
236
287
  }
237
- /* eslint-enable @typescript-eslint/no-unused-expressions */
238
- return mutate ? this : new LocalTime(d, this.utcMode);
288
+ return mutate ? this : new LocalTime(d);
289
+ }
290
+ endOf(unit, mutate = false) {
291
+ if (unit === 'second')
292
+ return this;
293
+ const d = mutate ? this.$date : new Date(this.$date);
294
+ d.setSeconds(59, 0);
295
+ if (unit !== 'minute') {
296
+ d.setMinutes(59);
297
+ if (unit !== 'hour') {
298
+ d.setHours(23);
299
+ if (unit !== 'day') {
300
+ // year, month or week
301
+ if (unit === 'year') {
302
+ d.setMonth(11);
303
+ }
304
+ if (unit === 'week') {
305
+ endOfWeek(d, true);
306
+ }
307
+ else {
308
+ // year or month
309
+ const lastDay = localDate_1.LocalDate.getMonthLength(d.getFullYear(), d.getMonth() + 1);
310
+ d.setDate(lastDay);
311
+ }
312
+ }
313
+ }
314
+ }
315
+ return mutate ? this : new LocalTime(d);
239
316
  }
240
317
  static sort(items, mutate = false, descending = false) {
241
318
  const mod = descending ? -1 : 1;
@@ -252,14 +329,18 @@ class LocalTime {
252
329
  }
253
330
  static earliest(items) {
254
331
  (0, assert_1._assert)(items.length, 'LocalTime.earliest called on empty array');
255
- return items.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
332
+ return items
333
+ .map(i => LocalTime.of(i))
334
+ .reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
256
335
  }
257
336
  static latestOrUndefined(items) {
258
337
  return items.length ? LocalTime.latest(items) : undefined;
259
338
  }
260
339
  static latest(items) {
261
340
  (0, assert_1._assert)(items.length, 'LocalTime.latest called on empty array');
262
- return items.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
341
+ return items
342
+ .map(i => LocalTime.of(i))
343
+ .reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
263
344
  }
264
345
  isSame(d) {
265
346
  return this.cmp(d) === 0;
@@ -299,18 +380,7 @@ class LocalTime {
299
380
  return 0;
300
381
  return t1 < t2 ? -1 : 1;
301
382
  }
302
- // todo: endOf
303
383
  components() {
304
- if (this.utcMode) {
305
- return {
306
- year: this.$date.getUTCFullYear(),
307
- month: this.$date.getUTCMonth() + 1,
308
- day: this.$date.getUTCDate(),
309
- hour: this.$date.getUTCHours(),
310
- minute: this.$date.getUTCMinutes(),
311
- second: this.$date.getSeconds(),
312
- };
313
- }
314
384
  return {
315
385
  year: this.$date.getFullYear(),
316
386
  month: this.$date.getMonth() + 1,
@@ -333,7 +403,7 @@ class LocalTime {
333
403
  return this.$date;
334
404
  }
335
405
  clone() {
336
- return new LocalTime(new Date(this.$date), this.utcMode);
406
+ return new LocalTime(new Date(this.$date));
337
407
  }
338
408
  unix() {
339
409
  return Math.floor(this.$date.valueOf() / 1000);
@@ -345,9 +415,6 @@ class LocalTime {
345
415
  return Math.floor(this.$date.valueOf() / 1000);
346
416
  }
347
417
  toLocalDate() {
348
- if (this.utcMode) {
349
- return localDate_1.LocalDate.create(this.$date.getUTCFullYear(), this.$date.getUTCMonth() + 1, this.$date.getUTCDate());
350
- }
351
418
  return localDate_1.LocalDate.create(this.$date.getFullYear(), this.$date.getMonth() + 1, this.$date.getDate());
352
419
  }
353
420
  toPretty(seconds = true) {
@@ -424,6 +491,9 @@ class LocalTime {
424
491
  toJSON() {
425
492
  return this.unix();
426
493
  }
494
+ format(fmt) {
495
+ return fmt(this);
496
+ }
427
497
  }
428
498
  exports.LocalTime = LocalTime;
429
499
  /**
@@ -433,3 +503,83 @@ function localTime(d) {
433
503
  return d ? LocalTime.of(d) : LocalTime.now();
434
504
  }
435
505
  exports.localTime = localTime;
506
+ // based on: https://github.com/date-fns/date-fns/blob/master/src/getISOWeek/index.ts
507
+ function getWeek(date) {
508
+ const diff = startOfWeek(date).getTime() - startOfWeekYear(date).getTime();
509
+ return Math.round(diff / MILLISECONDS_IN_WEEK) + 1;
510
+ }
511
+ function setWeek(date, week, mutate = false) {
512
+ const d = mutate ? date : new Date(date);
513
+ const diff = getWeek(d) - week;
514
+ d.setDate(d.getDate() - diff * 7);
515
+ return d;
516
+ }
517
+ // based on: https://github.com/date-fns/date-fns/blob/master/src/startOfISOWeekYear/index.ts
518
+ function startOfWeekYear(date) {
519
+ const year = getWeekYear(date);
520
+ const fourthOfJanuary = new Date(0);
521
+ fourthOfJanuary.setFullYear(year, 0, 4);
522
+ fourthOfJanuary.setHours(0, 0, 0, 0);
523
+ return startOfWeek(fourthOfJanuary, true);
524
+ }
525
+ // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/getISOWeekYear/index.ts
526
+ function getWeekYear(date) {
527
+ const year = date.getFullYear();
528
+ const fourthOfJanuaryOfNextYear = new Date(0);
529
+ fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
530
+ fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
531
+ const startOfNextYear = startOfWeek(fourthOfJanuaryOfNextYear, true);
532
+ const fourthOfJanuaryOfThisYear = new Date(0);
533
+ fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
534
+ fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
535
+ const startOfThisYear = startOfWeek(fourthOfJanuaryOfThisYear, true);
536
+ if (date.getTime() >= startOfNextYear.getTime()) {
537
+ return year + 1;
538
+ }
539
+ else if (date.getTime() >= startOfThisYear.getTime()) {
540
+ return year;
541
+ }
542
+ else {
543
+ return year - 1;
544
+ }
545
+ }
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
+ // based on: https://github.com/date-fns/date-fns/blob/fd6bb1a0bab143f2da068c05a9c562b9bee1357d/src/startOfWeek/index.ts
570
+ function startOfWeek(date, mutate = false) {
571
+ const d = mutate ? date : new Date(date);
572
+ const day = d.getDay();
573
+ const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
574
+ d.setDate(d.getDate() - diff);
575
+ d.setHours(0, 0, 0, 0);
576
+ return d;
577
+ }
578
+ // based on: https://github.com/date-fns/date-fns/blob/master/src/endOfWeek/index.ts
579
+ function endOfWeek(date, mutate = false) {
580
+ const d = mutate ? date : new Date(date);
581
+ const day = d.getDay();
582
+ const diff = (day < weekStartsOn ? -7 : 0) + 6 - (day - weekStartsOn);
583
+ d.setDate(d.getDate() + diff);
584
+ return d;
585
+ }
package/dist/index.d.ts CHANGED
@@ -64,9 +64,9 @@ export * from './datetime/localDate';
64
64
  export * from './datetime/localTime';
65
65
  export * from './datetime/dateInterval';
66
66
  export * from './datetime/timeInterval';
67
- import { LocalDateConfig, LocalDateUnit, Inclusiveness } from './datetime/localDate';
68
- import { LocalTimeConfig, LocalTimeUnit, LocalTimeComponents } from './datetime/localTime';
67
+ import { LocalDateConfig, LocalDateFormatter, LocalDateUnit, LocalDateUnitStrict, Inclusiveness } from './datetime/localDate';
68
+ import { LocalTimeConfig, LocalTimeFormatter, LocalTimeUnit, LocalTimeComponents, ISODayOfWeek } from './datetime/localTime';
69
69
  import { DateIntervalConfig, DateIntervalString } from './datetime/dateInterval';
70
70
  import { TimeIntervalConfig, TimeIntervalString } from './datetime/timeInterval';
71
- export type { DateIntervalConfig, DateIntervalString, TimeIntervalConfig, TimeIntervalString, LocalDateConfig, LocalDateUnit, Inclusiveness, LocalTimeConfig, LocalTimeUnit, LocalTimeComponents, AbortableMapper, AbortablePredicate, AbortableAsyncPredicate, AbortableAsyncMapper, PQueueCfg, MemoCache, AsyncMemoCache, PromiseDecoratorCfg, PromiseDecoratorResp, ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Admin401ErrorData, Admin403ErrorData, StringMap, PromiseMap, AnyObject, AnyFunction, ValuesOf, ValueOf, KeyValueTuple, ObjectMapper, ObjectPredicate, InstanceId, IsoDate, IsoDateString, IsoDateTimeString, Reviver, PMapOptions, Mapper, AsyncMapper, Predicate, AsyncPredicate, BatchResult, DeferredPromise, PRetryOptions, PTimeoutOptions, TryCatchOptions, StringifyAnyOptions, JsonStringifyFunction, Merge, ReadonlyDeep, Promisable, Simplify, ConditionalPick, ConditionalExcept, Class, UnixTimestampNumber, UnixTimestamp, Integer, BaseDBEntity, SavedDBEntity, Saved, Unsaved, UnsavedId, CreatedUpdated, CreatedUpdatedId, ObjectWithId, AnyObjectWithId, JsonSchema, JsonSchemaAny, JsonSchemaOneOf, JsonSchemaAllOf, JsonSchemaAnyOf, JsonSchemaNot, JsonSchemaRef, JsonSchemaConst, JsonSchemaEnum, JsonSchemaString, JsonSchemaNumber, JsonSchemaBoolean, JsonSchemaNull, JsonSchemaRootObject, JsonSchemaObject, JsonSchemaArray, JsonSchemaTuple, JsonSchemaBuilder, CommonLogLevel, CommonLogWithLevelFunction, CommonLogFunction, CommonLogger, };
71
+ export type { DateIntervalConfig, DateIntervalString, TimeIntervalConfig, TimeIntervalString, LocalDateConfig, LocalDateFormatter, LocalDateUnit, LocalDateUnitStrict, Inclusiveness, LocalTimeConfig, LocalTimeFormatter, LocalTimeUnit, ISODayOfWeek, LocalTimeComponents, AbortableMapper, AbortablePredicate, AbortableAsyncPredicate, AbortableAsyncMapper, PQueueCfg, MemoCache, AsyncMemoCache, PromiseDecoratorCfg, PromiseDecoratorResp, ErrorData, ErrorObject, HttpErrorData, HttpErrorResponse, Admin401ErrorData, Admin403ErrorData, StringMap, PromiseMap, AnyObject, AnyFunction, ValuesOf, ValueOf, KeyValueTuple, ObjectMapper, ObjectPredicate, InstanceId, IsoDate, IsoDateString, IsoDateTimeString, Reviver, PMapOptions, Mapper, AsyncMapper, Predicate, AsyncPredicate, BatchResult, DeferredPromise, PRetryOptions, PTimeoutOptions, TryCatchOptions, StringifyAnyOptions, JsonStringifyFunction, Merge, ReadonlyDeep, Promisable, Simplify, ConditionalPick, ConditionalExcept, Class, UnixTimestampNumber, UnixTimestamp, Integer, BaseDBEntity, SavedDBEntity, Saved, Unsaved, UnsavedId, CreatedUpdated, CreatedUpdatedId, ObjectWithId, AnyObjectWithId, JsonSchema, JsonSchemaAny, JsonSchemaOneOf, JsonSchemaAllOf, JsonSchemaAnyOf, JsonSchemaNot, JsonSchemaRef, JsonSchemaConst, JsonSchemaEnum, JsonSchemaString, JsonSchemaNumber, JsonSchemaBoolean, JsonSchemaNull, JsonSchemaRootObject, JsonSchemaObject, JsonSchemaArray, JsonSchemaTuple, JsonSchemaBuilder, CommonLogLevel, CommonLogWithLevelFunction, CommonLogFunction, CommonLogger, };
72
72
  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/dist/index.js CHANGED
@@ -96,3 +96,4 @@ tslib_1.__exportStar(require("./datetime/localDate"), exports);
96
96
  tslib_1.__exportStar(require("./datetime/localTime"), exports);
97
97
  tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
98
98
  tslib_1.__exportStar(require("./datetime/timeInterval"), exports);
99
+ const localTime_1 = require("./datetime/localTime");
@@ -1,4 +1,6 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
2
4
  /// <reference lib="es2018" />
3
5
  /// <reference lib="dom" />
4
6
  import { Class, ObservableLike, Primitive, TypedArray } from '../typeFest';
@@ -237,8 +237,37 @@ export function _shuffle(array, mutate = false) {
237
237
  return a;
238
238
  }
239
239
  /**
240
- * Returns last item of the array (or undefined if array is empty).
240
+ * Returns last item of non-empty array.
241
+ * Throws if array is empty.
241
242
  */
242
243
  export function _last(array) {
244
+ if (!array.length)
245
+ throw new Error('_last called on empty array');
246
+ return array[array.length - 1];
247
+ }
248
+ /**
249
+ * Returns last item of the array (or undefined if array is empty).
250
+ */
251
+ export function _lastOrUndefined(array) {
243
252
  return array[array.length - 1];
244
253
  }
254
+ export function _minOrUndefined(array) {
255
+ if (!array.length)
256
+ return;
257
+ return _min(array);
258
+ }
259
+ export function _min(array) {
260
+ if (!array.length)
261
+ throw new Error('_min called on empty array');
262
+ return array.reduce((min, item) => (min <= item ? min : item));
263
+ }
264
+ export function _maxOrUndefined(array) {
265
+ if (!array.length)
266
+ return;
267
+ return _max(array);
268
+ }
269
+ export function _max(array) {
270
+ if (!array.length)
271
+ throw new Error('_max called on empty array');
272
+ return array.reduce((max, item) => (max >= item ? max : item));
273
+ }
@@ -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.reduce((min, item) => (min.isSameOrBefore(item) ? min : item));
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.reduce((max, item) => (max.isSameOrAfter(item) ? max : item));
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);
@@ -194,44 +202,58 @@ export class LocalDate {
194
202
  return Math.abs(this.diff(d, unit));
195
203
  }
196
204
  /**
197
- * Returns the number of **full** units difference (aka `Math.ceil`).
205
+ * Returns the number of **full** units difference (aka `Math.floor`).
198
206
  *
199
207
  * a.diff(b) means "a minus b"
200
208
  */
201
209
  diff(d, unit) {
202
210
  d = LocalDate.of(d);
211
+ const sign = this.cmp(d);
212
+ if (!sign)
213
+ return 0;
214
+ // Put items in descending order: "big minus small"
215
+ const [big, small] = sign === 1 ? [this, d] : [d, this];
203
216
  if (unit === 'year') {
204
- return this.$year - d.$year;
217
+ let years = big.$year - small.$year;
218
+ if (big.$month < small.$month || (big.$month === small.$month && big.$day < small.$day)) {
219
+ years--;
220
+ }
221
+ return years * sign || 0;
205
222
  }
206
223
  if (unit === 'month') {
207
- return (this.$year - d.$year) * 12 + (this.$month - d.$month);
224
+ let months = (big.$year - small.$year) * 12 + (big.$month - small.$month);
225
+ if (big.$day < small.$day)
226
+ months--;
227
+ return months * sign || 0;
208
228
  }
209
- // unit is 'day'
210
- let days = this.$day - d.$day;
211
- if (d.$year < this.$year) {
212
- for (let year = d.$year; year < this.$year; year++) {
213
- days += LocalDate.getYearLength(year);
214
- }
229
+ // unit is 'day' or 'week'
230
+ let days = big.$day - small.$day;
231
+ // If small date is after 1st of March - next year's "leapness" should be used
232
+ const offsetYear = small.$month >= 3 ? 1 : 0;
233
+ for (let year = small.$year; year < big.$year; year++) {
234
+ days += LocalDate.getYearLength(year + offsetYear);
215
235
  }
216
- else if (this.$year < d.$year) {
217
- for (let year = this.$year; year < d.$year; year++) {
218
- days -= LocalDate.getYearLength(year);
236
+ if (small.$month < big.$month) {
237
+ for (let month = small.$month; month < big.$month; month++) {
238
+ days += LocalDate.getMonthLength(big.$year, month);
219
239
  }
220
240
  }
221
- if (d.$month < this.$month) {
222
- for (let month = d.$month; month < this.$month; month++) {
223
- days += LocalDate.getMonthLength(this.$year, month);
241
+ else if (big.$month < small.$month) {
242
+ for (let month = big.$month; month < small.$month; month++) {
243
+ days -= LocalDate.getMonthLength(big.$year, month);
224
244
  }
225
245
  }
226
- else if (this.$month < d.$month) {
227
- for (let month = this.$month; month < d.$month; month++) {
228
- days -= LocalDate.getMonthLength(d.$year, month);
229
- }
246
+ if (unit === 'week') {
247
+ return Math.trunc(days / 7) * sign || 0;
230
248
  }
231
- return days;
249
+ return days * sign || 0;
232
250
  }
233
251
  add(num, unit, mutate = false) {
234
252
  let { $day, $month, $year } = this;
253
+ if (unit === 'week') {
254
+ num *= 7;
255
+ unit = 'day';
256
+ }
235
257
  if (unit === 'day') {
236
258
  $day += num;
237
259
  }
@@ -361,6 +383,9 @@ export class LocalDate {
361
383
  toJSON() {
362
384
  return this.toString();
363
385
  }
386
+ format(fmt) {
387
+ return fmt(this);
388
+ }
364
389
  }
365
390
  /**
366
391
  * Shortcut wrapper around `LocalDate.parse` / `LocalDate.today`