@naturalcycles/js-lib 14.91.2 → 14.94.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.
@@ -1,6 +1,7 @@
1
1
  import { _assert } from '../error/assert'
2
+ import { _ms } from '../time/time.util'
2
3
  import { IsoDate, IsoDateTime, UnixTimestamp } from '../types'
3
- import { LocalDate } from './localDate'
4
+ import { Inclusiveness, LocalDate } from './localDate'
4
5
 
5
6
  export type LocalTimeUnit = 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'
6
7
 
@@ -26,11 +27,14 @@ export interface LocalTimeComponents {
26
27
  // .valueOf returns unix timestamp (no millis)
27
28
  // Prevents dayjs(undefined) being dayjs.now()
28
29
  // Validates on parse, throws if invalid. Doesn't allow invalid objects
30
+ // No arbitrary .format('') (which is slow to parse) vs well-defined (opinionated) formats
31
+ // Separate LocalTime, powered by native js Date, and LocalDate - a smaller functionality class when
32
+ // you only need "whole dates", no time, no timezone worry
29
33
  /**
30
34
  * @experimental
31
35
  */
32
36
  export class LocalTime {
33
- private constructor(private $date: Date) {}
37
+ private constructor(private $date: Date, public utcMode: boolean) {}
34
38
 
35
39
  /**
36
40
  * Parses input String into LocalDate.
@@ -46,6 +50,16 @@ export class LocalTime {
46
50
  return t
47
51
  }
48
52
 
53
+ utc(): this {
54
+ this.utcMode = true
55
+ return this
56
+ }
57
+
58
+ local(): this {
59
+ this.utcMode = false
60
+ return this
61
+ }
62
+
49
63
  /**
50
64
  * Returns null if invalid
51
65
  */
@@ -68,63 +82,65 @@ export class LocalTime {
68
82
  return null
69
83
  }
70
84
 
71
- return new LocalTime(date)
85
+ // if (utc) {
86
+ // date.setMinutes(date.getMinutes() + date.getTimezoneOffset())
87
+ // }
88
+
89
+ return new LocalTime(date, false)
72
90
  }
73
91
 
74
92
  static isValid(d: LocalTimeConfig): boolean {
75
93
  return this.parseOrNull(d) !== null
76
94
  }
77
95
 
78
- static unix(ts: UnixTimestamp): LocalTime {
79
- return new LocalTime(new Date(ts * 1000))
80
- }
81
-
82
96
  static now(): LocalTime {
83
- return this.of(new Date())
97
+ return new LocalTime(new Date(), false)
84
98
  }
85
99
 
86
100
  static fromComponents(
87
101
  c: { year: number; month: number } & Partial<LocalTimeComponents>,
88
102
  ): LocalTime {
89
- return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second))
103
+ return new LocalTime(new Date(c.year, c.month - 1, c.day, c.hour, c.minute, c.second), false)
90
104
  }
91
105
 
92
106
  get(unit: LocalTimeUnit): number {
93
107
  if (unit === 'year') {
94
- return this.$date.getFullYear()
108
+ return this.utcMode ? this.$date.getUTCFullYear() : this.$date.getFullYear()
95
109
  }
96
110
  if (unit === 'month') {
97
- return this.$date.getMonth() + 1
111
+ return (this.utcMode ? this.$date.getUTCMonth() : this.$date.getMonth()) + 1
98
112
  }
99
113
  if (unit === 'day') {
100
- return this.$date.getDate()
114
+ return this.utcMode ? this.$date.getUTCDate() : this.$date.getDate()
101
115
  }
102
116
  if (unit === 'hour') {
103
- return this.$date.getHours()
117
+ return this.utcMode ? this.$date.getUTCHours() : this.$date.getHours()
104
118
  }
105
119
  if (unit === 'minute') {
106
- return this.$date.getMinutes()
120
+ return this.utcMode ? this.$date.getUTCMinutes() : this.$date.getMinutes()
107
121
  }
108
122
  // second
109
- return this.$date.getSeconds()
123
+ return this.utcMode ? this.$date.getUTCSeconds() : this.$date.getSeconds()
110
124
  }
111
125
 
112
126
  set(unit: LocalTimeUnit, v: number, mutate = false): LocalTime {
113
127
  const t = mutate ? this : this.clone()
114
128
 
129
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
115
130
  if (unit === 'year') {
116
- t.$date.setFullYear(v)
131
+ this.utcMode ? t.$date.setUTCFullYear(v) : t.$date.setFullYear(v)
117
132
  } else if (unit === 'month') {
118
- t.$date.setMonth(v - 1)
133
+ this.utcMode ? t.$date.setUTCMonth(v - 1) : t.$date.setMonth(v - 1)
119
134
  } else if (unit === 'day') {
120
- t.$date.setDate(v)
135
+ this.utcMode ? t.$date.setUTCDate(v) : t.$date.setDate(v)
121
136
  } else if (unit === 'hour') {
122
- t.$date.setHours(v)
137
+ this.utcMode ? t.$date.setUTCHours(v) : t.$date.setHours(v)
123
138
  } else if (unit === 'minute') {
124
- t.$date.setMinutes(v)
139
+ this.utcMode ? t.$date.setUTCMinutes(v) : t.$date.setMinutes(v)
125
140
  } else if (unit === 'second') {
126
- t.$date.setSeconds(v)
141
+ this.utcMode ? t.$date.setUTCSeconds(v) : t.$date.setSeconds(v)
127
142
  }
143
+ /* eslint-enable @typescript-eslint/no-unused-expressions */
128
144
 
129
145
  return t
130
146
  }
@@ -132,57 +148,59 @@ export class LocalTime {
132
148
  year(): number
133
149
  year(v: number): LocalTime
134
150
  year(v?: number): number | LocalTime {
135
- return v === undefined ? this.$date.getFullYear() : this.set('year', v)
151
+ return v === undefined ? this.get('year') : this.set('year', v)
136
152
  }
137
153
  month(): number
138
154
  month(v: number): LocalTime
139
155
  month(v?: number): number | LocalTime {
140
- return v === undefined ? this.$date.getMonth() + 1 : this.set('month', v)
156
+ return v === undefined ? this.get('month') : this.set('month', v)
141
157
  }
142
158
  date(): number
143
159
  date(v: number): LocalTime
144
160
  date(v?: number): number | LocalTime {
145
- return v === undefined ? this.$date.getDate() : this.set('day', v)
161
+ return v === undefined ? this.get('day') : this.set('day', v)
146
162
  }
147
163
  hour(): number
148
164
  hour(v: number): LocalTime
149
165
  hour(v?: number): number | LocalTime {
150
- return v === undefined ? this.$date.getHours() : this.set('hour', v)
166
+ return v === undefined ? this.get('hour') : this.set('hour', v)
151
167
  }
152
168
  minute(): number
153
169
  minute(v: number): LocalTime
154
170
  minute(v?: number): number | LocalTime {
155
- return v === undefined ? this.$date.getMinutes() : this.set('minute', v)
171
+ return v === undefined ? this.get('minute') : this.set('minute', v)
156
172
  }
157
173
  second(): number
158
174
  second(v: number): LocalTime
159
175
  second(v?: number): number | LocalTime {
160
- return v === undefined ? this.$date.getSeconds() : this.set('second', v)
176
+ return v === undefined ? this.get('second') : this.set('second', v)
161
177
  }
162
178
 
163
179
  setComponents(c: Partial<LocalTimeComponents>, mutate = false): LocalTime {
164
180
  const d = mutate ? this.$date : new Date(this.$date)
165
181
 
182
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
166
183
  if (c.year) {
167
- d.setFullYear(c.year)
184
+ this.utcMode ? d.setUTCFullYear(c.year) : d.setFullYear(c.year)
168
185
  }
169
186
  if (c.month) {
170
- d.setMonth(c.month - 1)
187
+ this.utcMode ? d.setUTCMonth(c.month - 1) : d.setMonth(c.month - 1)
171
188
  }
172
189
  if (c.day) {
173
- d.setDate(c.day)
190
+ this.utcMode ? d.setUTCDate(c.day) : d.setDate(c.day)
174
191
  }
175
192
  if (c.hour !== undefined) {
176
- d.setHours(c.hour)
193
+ this.utcMode ? d.setUTCHours(c.hour) : d.setHours(c.hour)
177
194
  }
178
195
  if (c.minute !== undefined) {
179
- d.setMinutes(c.minute)
196
+ this.utcMode ? d.setUTCMinutes(c.minute) : d.setMinutes(c.minute)
180
197
  }
181
198
  if (c.second !== undefined) {
182
- d.setSeconds(c.second)
199
+ this.utcMode ? d.setUTCSeconds(c.second) : d.setSeconds(c.second)
183
200
  }
201
+ /* eslint-enable @typescript-eslint/no-unused-expressions */
184
202
 
185
- return mutate ? this : new LocalTime(d)
203
+ return mutate ? this : new LocalTime(d, this.utcMode)
186
204
  }
187
205
 
188
206
  add(num: number, unit: LocalTimeUnit, mutate = false): LocalTime {
@@ -190,7 +208,7 @@ export class LocalTime {
190
208
  }
191
209
 
192
210
  subtract(num: number, unit: LocalTimeUnit, mutate = false): LocalTime {
193
- return this.add(-num, unit, mutate)
211
+ return this.add(num * -1, unit, mutate)
194
212
  }
195
213
 
196
214
  absDiff(other: LocalTimeConfig, unit: LocalTimeUnit): number {
@@ -233,36 +251,25 @@ export class LocalTime {
233
251
  startOf(unit: LocalTimeUnit, mutate = false): LocalTime {
234
252
  if (unit === 'second') return this
235
253
 
236
- if (mutate) {
237
- const d = this.$date
238
- d.setSeconds(0)
239
- if (unit === 'minute') return this
240
- d.setMinutes(0)
241
- if (unit === 'hour') return this
242
- d.setHours(0)
243
- if (unit === 'day') return this
244
- d.setDate(0)
245
- if (unit === 'month') return this
246
- d.setMonth(0)
247
- return this
248
- }
249
-
250
- const c = this.components()
254
+ const d = mutate ? this.$date : new Date(this.$date)
251
255
 
252
- c.second = 0
253
- if (unit === 'year') {
254
- c.month = c.day = 1
255
- c.hour = c.minute = 0
256
- } else if (unit === 'month') {
257
- c.day = 1
258
- c.hour = c.minute = 0
259
- } else if (unit === 'day') {
260
- c.hour = c.minute = 0
261
- } else if (unit === 'hour') {
262
- c.minute = 0
256
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
257
+ this.utcMode ? d.setUTCSeconds(0) : d.setSeconds(0)
258
+ if (unit !== 'minute') {
259
+ this.utcMode ? d.setUTCMinutes(0) : d.setMinutes(0)
260
+ if (unit !== 'hour') {
261
+ this.utcMode ? d.setUTCHours(0) : d.setHours(0)
262
+ if (unit !== 'day') {
263
+ this.utcMode ? d.setUTCDate(0) : d.setDate(0)
264
+ if (unit !== 'month') {
265
+ this.utcMode ? d.setUTCMonth(0) : d.setMonth(0)
266
+ }
267
+ }
268
+ }
263
269
  }
270
+ /* eslint-enable @typescript-eslint/no-unused-expressions */
264
271
 
265
- return LocalTime.fromComponents(c)
272
+ return mutate ? this : new LocalTime(d, this.utcMode)
266
273
  }
267
274
 
268
275
  static sort(items: LocalTime[], mutate = false, descending = false): LocalTime[] {
@@ -315,6 +322,14 @@ export class LocalTime {
315
322
  return this.cmp(d) >= 0
316
323
  }
317
324
 
325
+ isBetween(min: LocalTimeConfig, max: LocalTimeConfig, incl: Inclusiveness = '[)'): boolean {
326
+ let r = this.cmp(min)
327
+ if (r < 0 || (r === 0 && incl[0] === '(')) return false
328
+ r = this.cmp(max)
329
+ if (r > 0 || (r === 0 && incl[1] === ')')) return false
330
+ return true
331
+ }
332
+
318
333
  /**
319
334
  * Returns 1 if this > d
320
335
  * returns 0 if they are equal
@@ -330,6 +345,17 @@ export class LocalTime {
330
345
  // todo: endOf
331
346
 
332
347
  components(): LocalTimeComponents {
348
+ if (this.utcMode) {
349
+ return {
350
+ year: this.$date.getUTCFullYear(),
351
+ month: this.$date.getUTCMonth() + 1,
352
+ day: this.$date.getUTCDate(),
353
+ hour: this.$date.getUTCHours(),
354
+ minute: this.$date.getUTCMinutes(),
355
+ second: this.$date.getSeconds(),
356
+ }
357
+ }
358
+
333
359
  return {
334
360
  year: this.$date.getFullYear(),
335
361
  month: this.$date.getMonth() + 1,
@@ -340,12 +366,24 @@ export class LocalTime {
340
366
  }
341
367
  }
342
368
 
369
+ fromNow(now: LocalTimeConfig = LocalTime.now()): string {
370
+ const msDiff = LocalTime.of(now).unixMillis() - this.unixMillis()
371
+
372
+ if (msDiff === 0) return 'now'
373
+
374
+ if (msDiff >= 0) {
375
+ return `${_ms(msDiff)} ago`
376
+ }
377
+
378
+ return `in ${_ms(msDiff * -1)}`
379
+ }
380
+
343
381
  getDate(): Date {
344
382
  return this.$date
345
383
  }
346
384
 
347
385
  clone(): LocalTime {
348
- return new LocalTime(new Date(this.$date))
386
+ return new LocalTime(new Date(this.$date), this.utcMode)
349
387
  }
350
388
 
351
389
  unix(): UnixTimestamp {
@@ -361,6 +399,14 @@ export class LocalTime {
361
399
  }
362
400
 
363
401
  toLocalDate(): LocalDate {
402
+ if (this.utcMode) {
403
+ return LocalDate.create(
404
+ this.$date.getUTCFullYear(),
405
+ this.$date.getUTCMonth() + 1,
406
+ this.$date.getUTCDate(),
407
+ )
408
+ }
409
+
364
410
  return LocalDate.create(
365
411
  this.$date.getFullYear(),
366
412
  this.$date.getMonth() + 1,
@@ -369,11 +415,29 @@ export class LocalTime {
369
415
  }
370
416
 
371
417
  toPretty(seconds = true): IsoDateTime {
372
- return this.$date
373
- .toISOString()
374
- .slice(0, seconds ? 19 : 16)
375
- .split('T')
376
- .join(' ')
418
+ const { year, month, day, hour, minute, second } = this.components()
419
+
420
+ return (
421
+ [
422
+ String(year).padStart(4, '0'),
423
+ String(month).padStart(2, '0'),
424
+ String(day).padStart(2, '0'),
425
+ ].join('-') +
426
+ ' ' +
427
+ [
428
+ String(hour).padStart(2, '0'),
429
+ String(minute).padStart(2, '0'),
430
+ seconds && String(second).padStart(2, '0'),
431
+ ]
432
+ .filter(Boolean)
433
+ .join(':')
434
+ )
435
+
436
+ // return this.$date
437
+ // .toISOString()
438
+ // .slice(0, seconds ? 19 : 16)
439
+ // .split('T')
440
+ // .join(' ')
377
441
  }
378
442
 
379
443
  /**
@@ -387,21 +451,47 @@ export class LocalTime {
387
451
  * Returns e.g: `1984-06-21`, only the date part of DateTime
388
452
  */
389
453
  toISODate(): IsoDate {
390
- return this.$date.toISOString().slice(0, 10)
454
+ const { year, month, day } = this.components()
455
+
456
+ return [
457
+ String(year).padStart(4, '0'),
458
+ String(month).padStart(2, '0'),
459
+ String(day).padStart(2, '0'),
460
+ ].join('-')
461
+
462
+ // return this.$date.toISOString().slice(0, 10)
463
+ }
464
+
465
+ /**
466
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
467
+ */
468
+ toISOTime(seconds = true): string {
469
+ // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
470
+ const { hour, minute, second } = this.components()
471
+
472
+ return [
473
+ String(hour).padStart(2, '0'),
474
+ String(minute).padStart(2, '0'),
475
+ seconds && String(second).padStart(2, '0'),
476
+ ]
477
+ .filter(Boolean)
478
+ .join(':')
391
479
  }
392
480
 
393
481
  /**
394
482
  * Returns e.g: `19840621_1705`
395
483
  */
396
484
  toStringCompact(seconds = false): string {
485
+ const { year, month, day, hour, minute, second } = this.components()
486
+
397
487
  return [
398
- String(this.$date.getFullYear()).padStart(4, '0'),
399
- String(this.$date.getMonth() + 1).padStart(2, '0'),
400
- String(this.$date.getDate()).padStart(2, '0'),
488
+ String(year).padStart(4, '0'),
489
+ String(month).padStart(2, '0'),
490
+ String(day).padStart(2, '0'),
401
491
  '_',
402
- String(this.$date.getHours()).padStart(2, '0'),
403
- String(this.$date.getMinutes()).padStart(2, '0'),
404
- seconds ? String(this.$date.getSeconds()).padStart(2, '0') : '',
492
+ String(hour).padStart(2, '0'),
493
+ String(minute).padStart(2, '0'),
494
+ seconds ? String(second).padStart(2, '0') : '',
405
495
  ].join('')
406
496
  }
407
497
 
package/src/index.ts CHANGED
@@ -158,12 +158,16 @@ export * from './math/stack.util'
158
158
  export * from './string/leven'
159
159
  export * from './datetime/localDate'
160
160
  export * from './datetime/localTime'
161
- import { LocalDateConfig, LocalDateUnit } from './datetime/localDate'
161
+ export * from './datetime/dateInterval'
162
+ import { LocalDateConfig, LocalDateUnit, Inclusiveness } from './datetime/localDate'
162
163
  import { LocalTimeConfig, LocalTimeUnit, LocalTimeComponents } from './datetime/localTime'
164
+ import { DateIntervalConfig } from './datetime/dateInterval'
163
165
 
164
166
  export type {
167
+ DateIntervalConfig,
165
168
  LocalDateConfig,
166
169
  LocalDateUnit,
170
+ Inclusiveness,
167
171
  LocalTimeConfig,
168
172
  LocalTimeUnit,
169
173
  LocalTimeComponents,