@naturalcycles/js-lib 14.91.1 → 14.93.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,4 +1,5 @@
1
1
  import { _assert } from '../error/assert'
2
+ import { _ms } from '../time/time.util'
2
3
  import { IsoDate, IsoDateTime, UnixTimestamp } from '../types'
3
4
  import { LocalDate } from './localDate'
4
5
 
@@ -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[] {
@@ -330,6 +337,17 @@ export class LocalTime {
330
337
  // todo: endOf
331
338
 
332
339
  components(): LocalTimeComponents {
340
+ if (this.utcMode) {
341
+ return {
342
+ year: this.$date.getUTCFullYear(),
343
+ month: this.$date.getUTCMonth() + 1,
344
+ day: this.$date.getUTCDate(),
345
+ hour: this.$date.getUTCHours(),
346
+ minute: this.$date.getUTCMinutes(),
347
+ second: this.$date.getSeconds(),
348
+ }
349
+ }
350
+
333
351
  return {
334
352
  year: this.$date.getFullYear(),
335
353
  month: this.$date.getMonth() + 1,
@@ -340,23 +358,47 @@ export class LocalTime {
340
358
  }
341
359
  }
342
360
 
361
+ fromNow(now: LocalTimeConfig = LocalTime.now()): string {
362
+ const msDiff = LocalTime.of(now).unixMillis() - this.unixMillis()
363
+
364
+ if (msDiff === 0) return 'now'
365
+
366
+ if (msDiff >= 0) {
367
+ return `${_ms(msDiff)} ago`
368
+ }
369
+
370
+ return `in ${_ms(msDiff * -1)}`
371
+ }
372
+
343
373
  getDate(): Date {
344
374
  return this.$date
345
375
  }
346
376
 
347
377
  clone(): LocalTime {
348
- return new LocalTime(new Date(this.$date))
378
+ return new LocalTime(new Date(this.$date), this.utcMode)
349
379
  }
350
380
 
351
381
  unix(): UnixTimestamp {
352
382
  return Math.floor(this.$date.valueOf() / 1000)
353
383
  }
354
384
 
385
+ unixMillis(): number {
386
+ return this.$date.valueOf()
387
+ }
388
+
355
389
  valueOf(): UnixTimestamp {
356
390
  return Math.floor(this.$date.valueOf() / 1000)
357
391
  }
358
392
 
359
393
  toLocalDate(): LocalDate {
394
+ if (this.utcMode) {
395
+ return LocalDate.create(
396
+ this.$date.getUTCFullYear(),
397
+ this.$date.getUTCMonth() + 1,
398
+ this.$date.getUTCDate(),
399
+ )
400
+ }
401
+
360
402
  return LocalDate.create(
361
403
  this.$date.getFullYear(),
362
404
  this.$date.getMonth() + 1,
@@ -365,11 +407,29 @@ export class LocalTime {
365
407
  }
366
408
 
367
409
  toPretty(seconds = true): IsoDateTime {
368
- return this.$date
369
- .toISOString()
370
- .slice(0, seconds ? 19 : 16)
371
- .split('T')
372
- .join(' ')
410
+ const { year, month, day, hour, minute, second } = this.components()
411
+
412
+ return (
413
+ [
414
+ String(year).padStart(4, '0'),
415
+ String(month).padStart(2, '0'),
416
+ String(day).padStart(2, '0'),
417
+ ].join('-') +
418
+ ' ' +
419
+ [
420
+ String(hour).padStart(2, '0'),
421
+ String(minute).padStart(2, '0'),
422
+ seconds && String(second).padStart(2, '0'),
423
+ ]
424
+ .filter(Boolean)
425
+ .join(':')
426
+ )
427
+
428
+ // return this.$date
429
+ // .toISOString()
430
+ // .slice(0, seconds ? 19 : 16)
431
+ // .split('T')
432
+ // .join(' ')
373
433
  }
374
434
 
375
435
  /**
@@ -383,21 +443,47 @@ export class LocalTime {
383
443
  * Returns e.g: `1984-06-21`, only the date part of DateTime
384
444
  */
385
445
  toISODate(): IsoDate {
386
- return this.$date.toISOString().slice(0, 10)
446
+ const { year, month, day } = this.components()
447
+
448
+ return [
449
+ String(year).padStart(4, '0'),
450
+ String(month).padStart(2, '0'),
451
+ String(day).padStart(2, '0'),
452
+ ].join('-')
453
+
454
+ // return this.$date.toISOString().slice(0, 10)
455
+ }
456
+
457
+ /**
458
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
459
+ */
460
+ toISOTime(seconds = true): string {
461
+ // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
462
+ const { hour, minute, second } = this.components()
463
+
464
+ return [
465
+ String(hour).padStart(2, '0'),
466
+ String(minute).padStart(2, '0'),
467
+ seconds && String(second).padStart(2, '0'),
468
+ ]
469
+ .filter(Boolean)
470
+ .join(':')
387
471
  }
388
472
 
389
473
  /**
390
474
  * Returns e.g: `19840621_1705`
391
475
  */
392
476
  toStringCompact(seconds = false): string {
477
+ const { year, month, day, hour, minute, second } = this.components()
478
+
393
479
  return [
394
- String(this.$date.getFullYear()).padStart(4, '0'),
395
- String(this.$date.getMonth() + 1).padStart(2, '0'),
396
- String(this.$date.getDate()).padStart(2, '0'),
480
+ String(year).padStart(4, '0'),
481
+ String(month).padStart(2, '0'),
482
+ String(day).padStart(2, '0'),
397
483
  '_',
398
- String(this.$date.getHours()).padStart(2, '0'),
399
- String(this.$date.getMinutes()).padStart(2, '0'),
400
- seconds ? String(this.$date.getSeconds()).padStart(2, '0') : '',
484
+ String(hour).padStart(2, '0'),
485
+ String(minute).padStart(2, '0'),
486
+ seconds ? String(second).padStart(2, '0') : '',
401
487
  ].join('')
402
488
  }
403
489
 
package/src/index.ts CHANGED
@@ -158,10 +158,13 @@ export * from './math/stack.util'
158
158
  export * from './string/leven'
159
159
  export * from './datetime/localDate'
160
160
  export * from './datetime/localTime'
161
+ export * from './datetime/dateInterval'
161
162
  import { LocalDateConfig, LocalDateUnit } 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,
167
170
  LocalTimeConfig,