@naturalcycles/js-lib 14.236.0 → 14.238.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,6 @@
1
1
  import { Iterable2 } from '../iter/iterable2';
2
2
  import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, SortDirection, UnixTimestampMillisNumber, UnixTimestampNumber } from '../types';
3
- import { ISODayOfWeek, LocalTime } from './localTime';
3
+ import { DateObject, ISODayOfWeek, LocalTime } from './localTime';
4
4
  export type LocalDateUnit = LocalDateUnitStrict | 'week';
5
5
  export type LocalDateUnitStrict = 'year' | 'month' | 'day';
6
6
  export type LocalDateInput = LocalDate | Date | IsoDateString;
@@ -57,6 +57,10 @@ export declare class LocalDate {
57
57
  * Checks if this localDate is same or younger (>=) than "today" by X units.
58
58
  */
59
59
  isSameOrYoungerThan(n: number, unit: LocalDateUnit, today?: LocalDateInput): boolean;
60
+ getAgeInYears(today?: LocalDateInput): number;
61
+ getAgeInMonths(today?: LocalDateInput): number;
62
+ getAgeInDays(today?: LocalDateInput): number;
63
+ getAgeIn(unit: LocalDateUnit, today?: LocalDateInput): number;
60
64
  /**
61
65
  * Returns 1 if this > d
62
66
  * returns 0 if they are equal
@@ -103,6 +107,7 @@ export declare class LocalDate {
103
107
  * Unlike normal `.toDate` that uses browser's timezone by default.
104
108
  */
105
109
  toDateInUTC(): Date;
110
+ toDateObject(): DateObject;
106
111
  /**
107
112
  * Converts LocalDate to LocalTime with 0 hours, 0 minutes, 0 seconds.
108
113
  * LocalTime's Date will be in local timezone.
@@ -108,6 +108,18 @@ class LocalDate {
108
108
  isSameOrYoungerThan(n, unit, today) {
109
109
  return this.isSameOrAfter(exports.localDate.of(today || new Date()).plus(-n, unit));
110
110
  }
111
+ getAgeInYears(today) {
112
+ return this.getAgeIn('year', today);
113
+ }
114
+ getAgeInMonths(today) {
115
+ return this.getAgeIn('month', today);
116
+ }
117
+ getAgeInDays(today) {
118
+ return this.getAgeIn('day', today);
119
+ }
120
+ getAgeIn(unit, today) {
121
+ return exports.localDate.of(today || new Date()).diff(this, unit);
122
+ }
111
123
  /**
112
124
  * Returns 1 if this > d
113
125
  * returns 0 if they are equal
@@ -323,6 +335,13 @@ class LocalDate {
323
335
  toDateInUTC() {
324
336
  return new Date(this.toISODateTimeInUTC());
325
337
  }
338
+ toDateObject() {
339
+ return {
340
+ year: this.$year,
341
+ month: this.$month,
342
+ day: this.$day,
343
+ };
344
+ }
326
345
  /**
327
346
  * Converts LocalDate to LocalTime with 0 hours, 0 minutes, 0 seconds.
328
347
  * LocalTime's Date will be in local timezone.
@@ -1,5 +1,6 @@
1
1
  import type { Inclusiveness, IsoDateString, IsoDateTimeString, MonthId, NumberOfHours, NumberOfMinutes, SortDirection, UnixTimestampMillisNumber, UnixTimestampNumber } from '../types';
2
2
  import { LocalDate } from './localDate';
3
+ import { WallTime } from './wallTime';
3
4
  export type LocalTimeUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second';
4
5
  export declare enum ISODayOfWeek {
5
6
  MONDAY = 1,
@@ -12,13 +13,13 @@ export declare enum ISODayOfWeek {
12
13
  }
13
14
  export type LocalTimeInput = LocalTime | Date | IsoDateTimeString | UnixTimestampNumber;
14
15
  export type LocalTimeFormatter = (ld: LocalTime) => string;
15
- export type LocalTimeComponents = DateComponents & TimeComponents;
16
- interface DateComponents {
16
+ export type DateTimeObject = DateObject & TimeObject;
17
+ export interface DateObject {
17
18
  year: number;
18
19
  month: number;
19
20
  day: number;
20
21
  }
21
- interface TimeComponents {
22
+ export interface TimeObject {
22
23
  hour: number;
23
24
  minute: number;
24
25
  second: number;
@@ -36,6 +37,51 @@ export declare class LocalTime {
36
37
  * Opposite of `.utc()` method.
37
38
  */
38
39
  local(): LocalTime;
40
+ /**
41
+ * Returns [cloned] fake LocalTime that has yyyy-mm-dd hh:mm:ss in the provided timezone.
42
+ * It is a fake LocalTime in a sense that it's timezone is not real.
43
+ * See this ("common errors"): https://stackoverflow.com/a/15171030/4919972
44
+ * Fake also means that unixTimestamp of that new LocalDate is not the same.
45
+ * For that reason we return WallTime, and not a LocalTime.
46
+ * WallTime can be pretty-printed as Date-only, Time-only or DateAndTime.
47
+ *
48
+ * E.g `inTimezone('America/New_York').toISOTime()`
49
+ *
50
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
51
+ *
52
+ * @experimental
53
+ */
54
+ inTimezone(tz: string): WallTime;
55
+ /**
56
+ * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
57
+ * to the local time to get UTC time.
58
+ *
59
+ * E.g utcOffset for CEST is -120,
60
+ * which means that you need to add -120 minutes to the local time to get UTC time.
61
+ *
62
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
63
+ *
64
+ * If timezone (tz) is specified, e.g `America/New_York`,
65
+ * it will return the UTC offset for that timezone.
66
+ *
67
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
68
+ */
69
+ getUTCOffsetMinutes(tz?: string): NumberOfMinutes;
70
+ /**
71
+ * Same as getUTCOffsetMinutes, but rounded to hours.
72
+ *
73
+ * E.g for CEST it is -2.
74
+ *
75
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
76
+ *
77
+ * If timezone (tz) is specified, e.g `America/New_York`,
78
+ * it will return the UTC offset for that timezone.
79
+ */
80
+ getUTCOffsetHours(tz?: string): NumberOfHours;
81
+ /**
82
+ * Returns e.g `-05:00` for New_York winter time.
83
+ */
84
+ getUTCOffsetString(tz: string): string;
39
85
  get(unit: LocalTimeUnit): number;
40
86
  set(unit: LocalTimeUnit, v: number, mutate?: boolean): LocalTime;
41
87
  year(): number;
@@ -57,7 +103,7 @@ export declare class LocalTime {
57
103
  minute(v: number): LocalTime;
58
104
  second(): number;
59
105
  second(v: number): LocalTime;
60
- setComponents(c: Partial<LocalTimeComponents>, mutate?: boolean): LocalTime;
106
+ setComponents(c: Partial<DateTimeObject>, mutate?: boolean): LocalTime;
61
107
  plusSeconds(num: number): LocalTime;
62
108
  plusMinutes(num: number): LocalTime;
63
109
  plusHours(num: number): LocalTime;
@@ -117,15 +163,22 @@ export declare class LocalTime {
117
163
  * Checks if this localTime is same or younger (>=) than "now" by X units.
118
164
  */
119
165
  isSameOrYoungerThan(n: number, unit: LocalTimeUnit, now?: LocalTimeInput): boolean;
166
+ getAgeInYears(now?: LocalTimeInput): number;
167
+ getAgeInMonths(now?: LocalTimeInput): number;
168
+ getAgeInDays(now?: LocalTimeInput): number;
169
+ getAgeInHours(now?: LocalTimeInput): number;
170
+ getAgeInMinutes(now?: LocalTimeInput): number;
171
+ getAgeInSeconds(now?: LocalTimeInput): number;
172
+ getAgeIn(unit: LocalTimeUnit, now?: LocalTimeInput): number;
120
173
  /**
121
174
  * Returns 1 if this > d
122
175
  * returns 0 if they are equal
123
176
  * returns -1 if this < d
124
177
  */
125
178
  cmp(d: LocalTimeInput): -1 | 0 | 1;
126
- components(): LocalTimeComponents;
127
- private dateComponents;
128
- private timeComponents;
179
+ getDateTimeObject(): DateTimeObject;
180
+ getDateObject(): DateObject;
181
+ getTimeObject(): TimeObject;
129
182
  fromNow(now?: LocalTimeInput): string;
130
183
  getDate(): Date;
131
184
  clone(): LocalTime;
@@ -177,6 +230,19 @@ declare class LocalTimeFactory {
177
230
  parseToDate(d: LocalTimeInput): Date;
178
231
  parseToUnixTimestamp(d: LocalTimeInput): UnixTimestampNumber;
179
232
  isValid(d: LocalTimeInput | undefined | null): boolean;
233
+ /**
234
+ * Returns the IANA timezone e.g `Europe/Stockholm`.
235
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
236
+ */
237
+ getTimezone(): string;
238
+ /**
239
+ * Returns true if passed IANA timezone is valid/supported.
240
+ * E.g `Europe/Stockholm` is valid, but `Europe/Stockholm2` is not.
241
+ *
242
+ * This implementation is not optimized for performance. If you need frequent validation -
243
+ * consider caching the Intl.supportedValuesOf values as Set and reuse that.
244
+ */
245
+ isTimezoneValid(tz: string): boolean;
180
246
  now(): LocalTime;
181
247
  /**
182
248
  * Creates a LocalTime from the input, unless it's falsy - then returns undefined.
@@ -191,7 +257,7 @@ declare class LocalTimeFactory {
191
257
  fromComponents(c: {
192
258
  year: number;
193
259
  month: number;
194
- } & Partial<LocalTimeComponents>): LocalTime;
260
+ } & Partial<DateTimeObject>): LocalTime;
195
261
  sort(items: LocalTime[], dir?: SortDirection, mutate?: boolean): LocalTime[];
196
262
  minOrUndefined(items: LocalTimeInput[]): LocalTime | undefined;
197
263
  min(items: LocalTimeInput[]): LocalTime;
@@ -207,22 +273,4 @@ export declare const localTime: LocalTimeFn;
207
273
  Like Date.now(), but in seconds.
208
274
  */
209
275
  export declare function nowUnix(): UnixTimestampNumber;
210
- /**
211
- * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
212
- * to the local time to get UTC time.
213
- *
214
- * E.g utcOffset for CEST is -120,
215
- * which means that you need to add -120 minutes to the local time to get UTC time.
216
- *
217
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
218
- */
219
- export declare function getUTCOffsetMinutes(): NumberOfMinutes;
220
- /**
221
- * Same as getUTCOffsetMinutes, but rounded to hours.
222
- *
223
- * E.g for CEST it is -2.
224
- *
225
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
226
- */
227
- export declare function getUTCOffsetHours(): NumberOfHours;
228
276
  export {};
@@ -1,9 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getUTCOffsetHours = exports.getUTCOffsetMinutes = exports.nowUnix = exports.localTime = exports.LocalTime = exports.ISODayOfWeek = void 0;
3
+ exports.nowUnix = 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
+ const wallTime_1 = require("./wallTime");
7
8
  var ISODayOfWeek;
8
9
  (function (ISODayOfWeek) {
9
10
  ISODayOfWeek[ISODayOfWeek["MONDAY"] = 1] = "MONDAY";
@@ -38,6 +39,78 @@ class LocalTime {
38
39
  local() {
39
40
  return new LocalTime(new Date(this.$date.getTime()));
40
41
  }
42
+ /**
43
+ * Returns [cloned] fake LocalTime that has yyyy-mm-dd hh:mm:ss in the provided timezone.
44
+ * It is a fake LocalTime in a sense that it's timezone is not real.
45
+ * See this ("common errors"): https://stackoverflow.com/a/15171030/4919972
46
+ * Fake also means that unixTimestamp of that new LocalDate is not the same.
47
+ * For that reason we return WallTime, and not a LocalTime.
48
+ * WallTime can be pretty-printed as Date-only, Time-only or DateAndTime.
49
+ *
50
+ * E.g `inTimezone('America/New_York').toISOTime()`
51
+ *
52
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
53
+ *
54
+ * @experimental
55
+ */
56
+ inTimezone(tz) {
57
+ const d = new Date(this.$date.toLocaleString('en-US', { timeZone: tz }));
58
+ return new wallTime_1.WallTime({
59
+ year: d.getFullYear(),
60
+ month: d.getMonth() + 1,
61
+ day: d.getDate(),
62
+ hour: d.getHours(),
63
+ minute: d.getMinutes(),
64
+ second: d.getSeconds(),
65
+ });
66
+ }
67
+ /**
68
+ * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
69
+ * to the local time to get UTC time.
70
+ *
71
+ * E.g utcOffset for CEST is -120,
72
+ * which means that you need to add -120 minutes to the local time to get UTC time.
73
+ *
74
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
75
+ *
76
+ * If timezone (tz) is specified, e.g `America/New_York`,
77
+ * it will return the UTC offset for that timezone.
78
+ *
79
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
80
+ */
81
+ getUTCOffsetMinutes(tz) {
82
+ if (tz) {
83
+ // based on: https://stackoverflow.com/a/53652131/4919972
84
+ const nowTime = this.$date.getTime();
85
+ const tzTime = new Date(this.$date.toLocaleString('en-US', { timeZone: tz })).getTime();
86
+ return Math.round((tzTime - nowTime) / 60000) || 0;
87
+ }
88
+ return -this.$date.getTimezoneOffset() || 0;
89
+ }
90
+ /**
91
+ * Same as getUTCOffsetMinutes, but rounded to hours.
92
+ *
93
+ * E.g for CEST it is -2.
94
+ *
95
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
96
+ *
97
+ * If timezone (tz) is specified, e.g `America/New_York`,
98
+ * it will return the UTC offset for that timezone.
99
+ */
100
+ getUTCOffsetHours(tz) {
101
+ return Math.round(this.getUTCOffsetMinutes(tz) / 60);
102
+ }
103
+ /**
104
+ * Returns e.g `-05:00` for New_York winter time.
105
+ */
106
+ getUTCOffsetString(tz) {
107
+ const minutes = this.getUTCOffsetMinutes(tz);
108
+ const hours = Math.trunc(minutes / 60);
109
+ const sign = hours < 0 ? '-' : '+';
110
+ const h = String(Math.abs(hours)).padStart(2, '0');
111
+ const m = String(minutes % 60).padStart(2, '0');
112
+ return `${sign}${h}:${m}`;
113
+ }
41
114
  get(unit) {
42
115
  if (unit === 'year') {
43
116
  return this.$date.getFullYear();
@@ -345,6 +418,27 @@ class LocalTime {
345
418
  isSameOrYoungerThan(n, unit, now) {
346
419
  return this.isSameOrAfter(exports.localTime.of(now ?? new Date()).plus(-n, unit));
347
420
  }
421
+ getAgeInYears(now) {
422
+ return this.getAgeIn('year', now);
423
+ }
424
+ getAgeInMonths(now) {
425
+ return this.getAgeIn('month', now);
426
+ }
427
+ getAgeInDays(now) {
428
+ return this.getAgeIn('day', now);
429
+ }
430
+ getAgeInHours(now) {
431
+ return this.getAgeIn('hour', now);
432
+ }
433
+ getAgeInMinutes(now) {
434
+ return this.getAgeIn('minute', now);
435
+ }
436
+ getAgeInSeconds(now) {
437
+ return this.getAgeIn('second', now);
438
+ }
439
+ getAgeIn(unit, now) {
440
+ return exports.localTime.of(now ?? new Date()).diff(this, unit);
441
+ }
348
442
  /**
349
443
  * Returns 1 if this > d
350
444
  * returns 0 if they are equal
@@ -357,20 +451,20 @@ class LocalTime {
357
451
  return 0;
358
452
  return t1 < t2 ? -1 : 1;
359
453
  }
360
- components() {
454
+ getDateTimeObject() {
361
455
  return {
362
- ...this.dateComponents(),
363
- ...this.timeComponents(),
456
+ ...this.getDateObject(),
457
+ ...this.getTimeObject(),
364
458
  };
365
459
  }
366
- dateComponents() {
460
+ getDateObject() {
367
461
  return {
368
462
  year: this.$date.getFullYear(),
369
463
  month: this.$date.getMonth() + 1,
370
464
  day: this.$date.getDate(),
371
465
  };
372
466
  }
373
- timeComponents() {
467
+ getTimeObject() {
374
468
  return {
375
469
  hour: this.$date.getHours(),
376
470
  minute: this.$date.getMinutes(),
@@ -427,7 +521,7 @@ class LocalTime {
427
521
  * Returns e.g: `1984-06-21`, only the date part of DateTime
428
522
  */
429
523
  toISODate() {
430
- const { year, month, day } = this.dateComponents();
524
+ const { year, month, day } = this.getDateObject();
431
525
  return [
432
526
  String(year).padStart(4, '0'),
433
527
  String(month).padStart(2, '0'),
@@ -440,7 +534,7 @@ class LocalTime {
440
534
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
441
535
  */
442
536
  toISOTime(seconds = true) {
443
- const { hour, minute, second } = this.timeComponents();
537
+ const { hour, minute, second } = this.getTimeObject();
444
538
  return [
445
539
  String(hour).padStart(2, '0'),
446
540
  String(minute).padStart(2, '0'),
@@ -455,7 +549,7 @@ class LocalTime {
455
549
  * Returns e.g: `19840621_1705`
456
550
  */
457
551
  toStringCompact(seconds = false) {
458
- const { year, month, day, hour, minute, second } = this.components();
552
+ const { year, month, day, hour, minute, second } = this.getDateTimeObject();
459
553
  return [
460
554
  String(year).padStart(4, '0'),
461
555
  String(month).padStart(2, '0'),
@@ -560,6 +654,23 @@ class LocalTimeFactory {
560
654
  isValid(d) {
561
655
  return this.parseOrNull(d) !== null;
562
656
  }
657
+ /**
658
+ * Returns the IANA timezone e.g `Europe/Stockholm`.
659
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
660
+ */
661
+ getTimezone() {
662
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
663
+ }
664
+ /**
665
+ * Returns true if passed IANA timezone is valid/supported.
666
+ * E.g `Europe/Stockholm` is valid, but `Europe/Stockholm2` is not.
667
+ *
668
+ * This implementation is not optimized for performance. If you need frequent validation -
669
+ * consider caching the Intl.supportedValuesOf values as Set and reuse that.
670
+ */
671
+ isTimezoneValid(tz) {
672
+ return Intl.supportedValuesOf('timeZone').includes(tz);
673
+ }
563
674
  now() {
564
675
  return new LocalTime(new Date());
565
676
  }
@@ -710,27 +821,3 @@ function nowUnix() {
710
821
  return Math.floor(Date.now() / 1000);
711
822
  }
712
823
  exports.nowUnix = nowUnix;
713
- /**
714
- * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
715
- * to the local time to get UTC time.
716
- *
717
- * E.g utcOffset for CEST is -120,
718
- * which means that you need to add -120 minutes to the local time to get UTC time.
719
- *
720
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
721
- */
722
- function getUTCOffsetMinutes() {
723
- return -new Date().getTimezoneOffset() || 0;
724
- }
725
- exports.getUTCOffsetMinutes = getUTCOffsetMinutes;
726
- /**
727
- * Same as getUTCOffsetMinutes, but rounded to hours.
728
- *
729
- * E.g for CEST it is -2.
730
- *
731
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
732
- */
733
- function getUTCOffsetHours() {
734
- return Math.round(getUTCOffsetMinutes() / 60);
735
- }
736
- exports.getUTCOffsetHours = getUTCOffsetHours;
@@ -0,0 +1,33 @@
1
+ import { DateTimeObject } from './localTime';
2
+ /**
3
+ * Representation of a "time on the wall clock",
4
+ * which means "local time, regardless of timezone".
5
+ *
6
+ * Experimental simplified container object to hold
7
+ * date and time components as numbers.
8
+ * No math or manipulation is possible here.
9
+ * Can be pretty-printed as Date, Time or DateAndTime.
10
+ */
11
+ export declare class WallTime implements DateTimeObject {
12
+ year: number;
13
+ month: number;
14
+ day: number;
15
+ hour: number;
16
+ minute: number;
17
+ second: number;
18
+ constructor(obj: DateTimeObject);
19
+ /**
20
+ * Returns e.g: `1984-06-21 17:56:21`
21
+ * or (if seconds=false):
22
+ * `1984-06-21 17:56`
23
+ */
24
+ toPretty(seconds?: boolean): string;
25
+ /**
26
+ * Returns e.g: `1984-06-21`, only the date part of DateTime
27
+ */
28
+ toISODate(): string;
29
+ /**
30
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
31
+ */
32
+ toISOTime(seconds?: boolean): string;
33
+ }
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WallTime = void 0;
4
+ /**
5
+ * Representation of a "time on the wall clock",
6
+ * which means "local time, regardless of timezone".
7
+ *
8
+ * Experimental simplified container object to hold
9
+ * date and time components as numbers.
10
+ * No math or manipulation is possible here.
11
+ * Can be pretty-printed as Date, Time or DateAndTime.
12
+ */
13
+ class WallTime {
14
+ constructor(obj) {
15
+ Object.assign(this, obj);
16
+ }
17
+ /**
18
+ * Returns e.g: `1984-06-21 17:56:21`
19
+ * or (if seconds=false):
20
+ * `1984-06-21 17:56`
21
+ */
22
+ toPretty(seconds = true) {
23
+ return this.toISODate() + ' ' + this.toISOTime(seconds);
24
+ }
25
+ /**
26
+ * Returns e.g: `1984-06-21`, only the date part of DateTime
27
+ */
28
+ toISODate() {
29
+ return [
30
+ String(this.year).padStart(4, '0'),
31
+ String(this.month).padStart(2, '0'),
32
+ String(this.day).padStart(2, '0'),
33
+ ].join('-');
34
+ }
35
+ /**
36
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
37
+ */
38
+ toISOTime(seconds = true) {
39
+ return [
40
+ String(this.hour).padStart(2, '0'),
41
+ String(this.minute).padStart(2, '0'),
42
+ seconds && String(this.second).padStart(2, '0'),
43
+ ]
44
+ .filter(Boolean)
45
+ .join(':');
46
+ }
47
+ }
48
+ exports.WallTime = WallTime;
package/dist/index.d.ts CHANGED
@@ -26,7 +26,6 @@ export * from './json-schema/jsonSchema.cnst';
26
26
  export * from './json-schema/jsonSchema.model';
27
27
  export * from './json-schema/jsonSchema.util';
28
28
  export * from './json-schema/jsonSchemaBuilder';
29
- export * from './json-schema/jsonSchemaBuilder';
30
29
  export * from './math/math.util';
31
30
  export * from './math/sma';
32
31
  export * from './number/createDeterministicRandom';
@@ -68,10 +67,7 @@ export * from './math/stack.util';
68
67
  export * from './string/leven';
69
68
  export * from './datetime/localDate';
70
69
  export * from './datetime/localTime';
71
- export * from './datetime/dateInterval';
72
- export * from './datetime/timeInterval';
73
- export * from './datetime/localDate';
74
- export * from './datetime/localTime';
70
+ export * from './datetime/wallTime';
75
71
  export * from './datetime/dateInterval';
76
72
  export * from './datetime/timeInterval';
77
73
  export * from './env';
package/dist/index.js CHANGED
@@ -30,7 +30,6 @@ tslib_1.__exportStar(require("./json-schema/jsonSchema.cnst"), exports);
30
30
  tslib_1.__exportStar(require("./json-schema/jsonSchema.model"), exports);
31
31
  tslib_1.__exportStar(require("./json-schema/jsonSchema.util"), exports);
32
32
  tslib_1.__exportStar(require("./json-schema/jsonSchemaBuilder"), exports);
33
- tslib_1.__exportStar(require("./json-schema/jsonSchemaBuilder"), exports);
34
33
  tslib_1.__exportStar(require("./math/math.util"), exports);
35
34
  tslib_1.__exportStar(require("./math/sma"), exports);
36
35
  tslib_1.__exportStar(require("./number/createDeterministicRandom"), exports);
@@ -72,10 +71,7 @@ tslib_1.__exportStar(require("./math/stack.util"), exports);
72
71
  tslib_1.__exportStar(require("./string/leven"), exports);
73
72
  tslib_1.__exportStar(require("./datetime/localDate"), exports);
74
73
  tslib_1.__exportStar(require("./datetime/localTime"), exports);
75
- tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
76
- tslib_1.__exportStar(require("./datetime/timeInterval"), exports);
77
- tslib_1.__exportStar(require("./datetime/localDate"), exports);
78
- tslib_1.__exportStar(require("./datetime/localTime"), exports);
74
+ tslib_1.__exportStar(require("./datetime/wallTime"), exports);
79
75
  tslib_1.__exportStar(require("./datetime/dateInterval"), exports);
80
76
  tslib_1.__exportStar(require("./datetime/timeInterval"), exports);
81
77
  tslib_1.__exportStar(require("./env"), exports);
@@ -105,6 +105,18 @@ export class LocalDate {
105
105
  isSameOrYoungerThan(n, unit, today) {
106
106
  return this.isSameOrAfter(localDate.of(today || new Date()).plus(-n, unit));
107
107
  }
108
+ getAgeInYears(today) {
109
+ return this.getAgeIn('year', today);
110
+ }
111
+ getAgeInMonths(today) {
112
+ return this.getAgeIn('month', today);
113
+ }
114
+ getAgeInDays(today) {
115
+ return this.getAgeIn('day', today);
116
+ }
117
+ getAgeIn(unit, today) {
118
+ return localDate.of(today || new Date()).diff(this, unit);
119
+ }
108
120
  /**
109
121
  * Returns 1 if this > d
110
122
  * returns 0 if they are equal
@@ -320,6 +332,13 @@ export class LocalDate {
320
332
  toDateInUTC() {
321
333
  return new Date(this.toISODateTimeInUTC());
322
334
  }
335
+ toDateObject() {
336
+ return {
337
+ year: this.$year,
338
+ month: this.$month,
339
+ day: this.$day,
340
+ };
341
+ }
323
342
  /**
324
343
  * Converts LocalDate to LocalTime with 0 hours, 0 minutes, 0 seconds.
325
344
  * LocalTime's Date will be in local timezone.
@@ -1,6 +1,7 @@
1
1
  import { _assert } from '../error/assert';
2
2
  import { _ms } from '../time/time.util';
3
3
  import { localDate } from './localDate';
4
+ import { WallTime } from './wallTime';
4
5
  export var ISODayOfWeek;
5
6
  (function (ISODayOfWeek) {
6
7
  ISODayOfWeek[ISODayOfWeek["MONDAY"] = 1] = "MONDAY";
@@ -35,6 +36,78 @@ export class LocalTime {
35
36
  local() {
36
37
  return new LocalTime(new Date(this.$date.getTime()));
37
38
  }
39
+ /**
40
+ * Returns [cloned] fake LocalTime that has yyyy-mm-dd hh:mm:ss in the provided timezone.
41
+ * It is a fake LocalTime in a sense that it's timezone is not real.
42
+ * See this ("common errors"): https://stackoverflow.com/a/15171030/4919972
43
+ * Fake also means that unixTimestamp of that new LocalDate is not the same.
44
+ * For that reason we return WallTime, and not a LocalTime.
45
+ * WallTime can be pretty-printed as Date-only, Time-only or DateAndTime.
46
+ *
47
+ * E.g `inTimezone('America/New_York').toISOTime()`
48
+ *
49
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
50
+ *
51
+ * @experimental
52
+ */
53
+ inTimezone(tz) {
54
+ const d = new Date(this.$date.toLocaleString('en-US', { timeZone: tz }));
55
+ return new WallTime({
56
+ year: d.getFullYear(),
57
+ month: d.getMonth() + 1,
58
+ day: d.getDate(),
59
+ hour: d.getHours(),
60
+ minute: d.getMinutes(),
61
+ second: d.getSeconds(),
62
+ });
63
+ }
64
+ /**
65
+ * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
66
+ * to the local time to get UTC time.
67
+ *
68
+ * E.g utcOffset for CEST is -120,
69
+ * which means that you need to add -120 minutes to the local time to get UTC time.
70
+ *
71
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
72
+ *
73
+ * If timezone (tz) is specified, e.g `America/New_York`,
74
+ * it will return the UTC offset for that timezone.
75
+ *
76
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
77
+ */
78
+ getUTCOffsetMinutes(tz) {
79
+ if (tz) {
80
+ // based on: https://stackoverflow.com/a/53652131/4919972
81
+ const nowTime = this.$date.getTime();
82
+ const tzTime = new Date(this.$date.toLocaleString('en-US', { timeZone: tz })).getTime();
83
+ return Math.round((tzTime - nowTime) / 60000) || 0;
84
+ }
85
+ return -this.$date.getTimezoneOffset() || 0;
86
+ }
87
+ /**
88
+ * Same as getUTCOffsetMinutes, but rounded to hours.
89
+ *
90
+ * E.g for CEST it is -2.
91
+ *
92
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
93
+ *
94
+ * If timezone (tz) is specified, e.g `America/New_York`,
95
+ * it will return the UTC offset for that timezone.
96
+ */
97
+ getUTCOffsetHours(tz) {
98
+ return Math.round(this.getUTCOffsetMinutes(tz) / 60);
99
+ }
100
+ /**
101
+ * Returns e.g `-05:00` for New_York winter time.
102
+ */
103
+ getUTCOffsetString(tz) {
104
+ const minutes = this.getUTCOffsetMinutes(tz);
105
+ const hours = Math.trunc(minutes / 60);
106
+ const sign = hours < 0 ? '-' : '+';
107
+ const h = String(Math.abs(hours)).padStart(2, '0');
108
+ const m = String(minutes % 60).padStart(2, '0');
109
+ return `${sign}${h}:${m}`;
110
+ }
38
111
  get(unit) {
39
112
  if (unit === 'year') {
40
113
  return this.$date.getFullYear();
@@ -342,6 +415,27 @@ export class LocalTime {
342
415
  isSameOrYoungerThan(n, unit, now) {
343
416
  return this.isSameOrAfter(localTime.of(now ?? new Date()).plus(-n, unit));
344
417
  }
418
+ getAgeInYears(now) {
419
+ return this.getAgeIn('year', now);
420
+ }
421
+ getAgeInMonths(now) {
422
+ return this.getAgeIn('month', now);
423
+ }
424
+ getAgeInDays(now) {
425
+ return this.getAgeIn('day', now);
426
+ }
427
+ getAgeInHours(now) {
428
+ return this.getAgeIn('hour', now);
429
+ }
430
+ getAgeInMinutes(now) {
431
+ return this.getAgeIn('minute', now);
432
+ }
433
+ getAgeInSeconds(now) {
434
+ return this.getAgeIn('second', now);
435
+ }
436
+ getAgeIn(unit, now) {
437
+ return localTime.of(now ?? new Date()).diff(this, unit);
438
+ }
345
439
  /**
346
440
  * Returns 1 if this > d
347
441
  * returns 0 if they are equal
@@ -354,20 +448,20 @@ export class LocalTime {
354
448
  return 0;
355
449
  return t1 < t2 ? -1 : 1;
356
450
  }
357
- components() {
451
+ getDateTimeObject() {
358
452
  return {
359
- ...this.dateComponents(),
360
- ...this.timeComponents(),
453
+ ...this.getDateObject(),
454
+ ...this.getTimeObject(),
361
455
  };
362
456
  }
363
- dateComponents() {
457
+ getDateObject() {
364
458
  return {
365
459
  year: this.$date.getFullYear(),
366
460
  month: this.$date.getMonth() + 1,
367
461
  day: this.$date.getDate(),
368
462
  };
369
463
  }
370
- timeComponents() {
464
+ getTimeObject() {
371
465
  return {
372
466
  hour: this.$date.getHours(),
373
467
  minute: this.$date.getMinutes(),
@@ -424,7 +518,7 @@ export class LocalTime {
424
518
  * Returns e.g: `1984-06-21`, only the date part of DateTime
425
519
  */
426
520
  toISODate() {
427
- const { year, month, day } = this.dateComponents();
521
+ const { year, month, day } = this.getDateObject();
428
522
  return [
429
523
  String(year).padStart(4, '0'),
430
524
  String(month).padStart(2, '0'),
@@ -437,7 +531,7 @@ export class LocalTime {
437
531
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
438
532
  */
439
533
  toISOTime(seconds = true) {
440
- const { hour, minute, second } = this.timeComponents();
534
+ const { hour, minute, second } = this.getTimeObject();
441
535
  return [
442
536
  String(hour).padStart(2, '0'),
443
537
  String(minute).padStart(2, '0'),
@@ -452,7 +546,7 @@ export class LocalTime {
452
546
  * Returns e.g: `19840621_1705`
453
547
  */
454
548
  toStringCompact(seconds = false) {
455
- const { year, month, day, hour, minute, second } = this.components();
549
+ const { year, month, day, hour, minute, second } = this.getDateTimeObject();
456
550
  return [
457
551
  String(year).padStart(4, '0'),
458
552
  String(month).padStart(2, '0'),
@@ -556,6 +650,23 @@ class LocalTimeFactory {
556
650
  isValid(d) {
557
651
  return this.parseOrNull(d) !== null;
558
652
  }
653
+ /**
654
+ * Returns the IANA timezone e.g `Europe/Stockholm`.
655
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
656
+ */
657
+ getTimezone() {
658
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
659
+ }
660
+ /**
661
+ * Returns true if passed IANA timezone is valid/supported.
662
+ * E.g `Europe/Stockholm` is valid, but `Europe/Stockholm2` is not.
663
+ *
664
+ * This implementation is not optimized for performance. If you need frequent validation -
665
+ * consider caching the Intl.supportedValuesOf values as Set and reuse that.
666
+ */
667
+ isTimezoneValid(tz) {
668
+ return Intl.supportedValuesOf('timeZone').includes(tz);
669
+ }
559
670
  now() {
560
671
  return new LocalTime(new Date());
561
672
  }
@@ -705,25 +816,3 @@ Object.setPrototypeOf(localTime, localTimeFactory);
705
816
  export function nowUnix() {
706
817
  return Math.floor(Date.now() / 1000);
707
818
  }
708
- /**
709
- * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
710
- * to the local time to get UTC time.
711
- *
712
- * E.g utcOffset for CEST is -120,
713
- * which means that you need to add -120 minutes to the local time to get UTC time.
714
- *
715
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
716
- */
717
- export function getUTCOffsetMinutes() {
718
- return -new Date().getTimezoneOffset() || 0;
719
- }
720
- /**
721
- * Same as getUTCOffsetMinutes, but rounded to hours.
722
- *
723
- * E.g for CEST it is -2.
724
- *
725
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
726
- */
727
- export function getUTCOffsetHours() {
728
- return Math.round(getUTCOffsetMinutes() / 60);
729
- }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Representation of a "time on the wall clock",
3
+ * which means "local time, regardless of timezone".
4
+ *
5
+ * Experimental simplified container object to hold
6
+ * date and time components as numbers.
7
+ * No math or manipulation is possible here.
8
+ * Can be pretty-printed as Date, Time or DateAndTime.
9
+ */
10
+ export class WallTime {
11
+ constructor(obj) {
12
+ Object.assign(this, obj);
13
+ }
14
+ /**
15
+ * Returns e.g: `1984-06-21 17:56:21`
16
+ * or (if seconds=false):
17
+ * `1984-06-21 17:56`
18
+ */
19
+ toPretty(seconds = true) {
20
+ return this.toISODate() + ' ' + this.toISOTime(seconds);
21
+ }
22
+ /**
23
+ * Returns e.g: `1984-06-21`, only the date part of DateTime
24
+ */
25
+ toISODate() {
26
+ return [
27
+ String(this.year).padStart(4, '0'),
28
+ String(this.month).padStart(2, '0'),
29
+ String(this.day).padStart(2, '0'),
30
+ ].join('-');
31
+ }
32
+ /**
33
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
34
+ */
35
+ toISOTime(seconds = true) {
36
+ return [
37
+ String(this.hour).padStart(2, '0'),
38
+ String(this.minute).padStart(2, '0'),
39
+ seconds && String(this.second).padStart(2, '0'),
40
+ ]
41
+ .filter(Boolean)
42
+ .join(':');
43
+ }
44
+ }
package/dist-esm/index.js CHANGED
@@ -26,7 +26,6 @@ export * from './json-schema/jsonSchema.cnst';
26
26
  export * from './json-schema/jsonSchema.model';
27
27
  export * from './json-schema/jsonSchema.util';
28
28
  export * from './json-schema/jsonSchemaBuilder';
29
- export * from './json-schema/jsonSchemaBuilder';
30
29
  export * from './math/math.util';
31
30
  export * from './math/sma';
32
31
  export * from './number/createDeterministicRandom';
@@ -68,10 +67,7 @@ export * from './math/stack.util';
68
67
  export * from './string/leven';
69
68
  export * from './datetime/localDate';
70
69
  export * from './datetime/localTime';
71
- export * from './datetime/dateInterval';
72
- export * from './datetime/timeInterval';
73
- export * from './datetime/localDate';
74
- export * from './datetime/localTime';
70
+ export * from './datetime/wallTime';
75
71
  export * from './datetime/dateInterval';
76
72
  export * from './datetime/timeInterval';
77
73
  export * from './env';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.236.0",
3
+ "version": "14.238.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -9,7 +9,7 @@ import type {
9
9
  UnixTimestampMillisNumber,
10
10
  UnixTimestampNumber,
11
11
  } from '../types'
12
- import { ISODayOfWeek, localTime, LocalTime } from './localTime'
12
+ import { DateObject, ISODayOfWeek, localTime, LocalTime } from './localTime'
13
13
 
14
14
  export type LocalDateUnit = LocalDateUnitStrict | 'week'
15
15
  export type LocalDateUnitStrict = 'year' | 'month' | 'day'
@@ -141,6 +141,19 @@ export class LocalDate {
141
141
  return this.isSameOrAfter(localDate.of(today || new Date()).plus(-n, unit))
142
142
  }
143
143
 
144
+ getAgeInYears(today?: LocalDateInput): number {
145
+ return this.getAgeIn('year', today)
146
+ }
147
+ getAgeInMonths(today?: LocalDateInput): number {
148
+ return this.getAgeIn('month', today)
149
+ }
150
+ getAgeInDays(today?: LocalDateInput): number {
151
+ return this.getAgeIn('day', today)
152
+ }
153
+ getAgeIn(unit: LocalDateUnit, today?: LocalDateInput): number {
154
+ return localDate.of(today || new Date()).diff(this, unit)
155
+ }
156
+
144
157
  /**
145
158
  * Returns 1 if this > d
146
159
  * returns 0 if they are equal
@@ -381,6 +394,14 @@ export class LocalDate {
381
394
  return new Date(this.toISODateTimeInUTC())
382
395
  }
383
396
 
397
+ toDateObject(): DateObject {
398
+ return {
399
+ year: this.$year,
400
+ month: this.$month,
401
+ day: this.$day,
402
+ }
403
+ }
404
+
384
405
  /**
385
406
  * Converts LocalDate to LocalTime with 0 hours, 0 minutes, 0 seconds.
386
407
  * LocalTime's Date will be in local timezone.
@@ -12,6 +12,7 @@ import type {
12
12
  UnixTimestampNumber,
13
13
  } from '../types'
14
14
  import { localDate, LocalDate } from './localDate'
15
+ import { WallTime } from './wallTime'
15
16
 
16
17
  export type LocalTimeUnit = 'year' | 'month' | 'week' | 'day' | 'hour' | 'minute' | 'second'
17
18
 
@@ -28,15 +29,15 @@ export enum ISODayOfWeek {
28
29
  export type LocalTimeInput = LocalTime | Date | IsoDateTimeString | UnixTimestampNumber
29
30
  export type LocalTimeFormatter = (ld: LocalTime) => string
30
31
 
31
- export type LocalTimeComponents = DateComponents & TimeComponents
32
+ export type DateTimeObject = DateObject & TimeObject
32
33
 
33
- interface DateComponents {
34
+ export interface DateObject {
34
35
  year: number
35
36
  month: number
36
37
  day: number
37
38
  }
38
39
 
39
- interface TimeComponents {
40
+ export interface TimeObject {
40
41
  hour: number
41
42
  minute: number
42
43
  second: number
@@ -68,6 +69,83 @@ export class LocalTime {
68
69
  return new LocalTime(new Date(this.$date.getTime()))
69
70
  }
70
71
 
72
+ /**
73
+ * Returns [cloned] fake LocalTime that has yyyy-mm-dd hh:mm:ss in the provided timezone.
74
+ * It is a fake LocalTime in a sense that it's timezone is not real.
75
+ * See this ("common errors"): https://stackoverflow.com/a/15171030/4919972
76
+ * Fake also means that unixTimestamp of that new LocalDate is not the same.
77
+ * For that reason we return WallTime, and not a LocalTime.
78
+ * WallTime can be pretty-printed as Date-only, Time-only or DateAndTime.
79
+ *
80
+ * E.g `inTimezone('America/New_York').toISOTime()`
81
+ *
82
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
83
+ *
84
+ * @experimental
85
+ */
86
+ inTimezone(tz: string): WallTime {
87
+ const d = new Date(this.$date.toLocaleString('en-US', { timeZone: tz }))
88
+ return new WallTime({
89
+ year: d.getFullYear(),
90
+ month: d.getMonth() + 1,
91
+ day: d.getDate(),
92
+ hour: d.getHours(),
93
+ minute: d.getMinutes(),
94
+ second: d.getSeconds(),
95
+ })
96
+ }
97
+
98
+ /**
99
+ * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
100
+ * to the local time to get UTC time.
101
+ *
102
+ * E.g utcOffset for CEST is -120,
103
+ * which means that you need to add -120 minutes to the local time to get UTC time.
104
+ *
105
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
106
+ *
107
+ * If timezone (tz) is specified, e.g `America/New_York`,
108
+ * it will return the UTC offset for that timezone.
109
+ *
110
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
111
+ */
112
+ getUTCOffsetMinutes(tz?: string): NumberOfMinutes {
113
+ if (tz) {
114
+ // based on: https://stackoverflow.com/a/53652131/4919972
115
+ const nowTime = this.$date.getTime()
116
+ const tzTime = new Date(this.$date.toLocaleString('en-US', { timeZone: tz })).getTime()
117
+ return Math.round((tzTime - nowTime) / 60000) || 0
118
+ }
119
+
120
+ return -this.$date.getTimezoneOffset() || 0
121
+ }
122
+
123
+ /**
124
+ * Same as getUTCOffsetMinutes, but rounded to hours.
125
+ *
126
+ * E.g for CEST it is -2.
127
+ *
128
+ * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
129
+ *
130
+ * If timezone (tz) is specified, e.g `America/New_York`,
131
+ * it will return the UTC offset for that timezone.
132
+ */
133
+ getUTCOffsetHours(tz?: string): NumberOfHours {
134
+ return Math.round(this.getUTCOffsetMinutes(tz) / 60)
135
+ }
136
+
137
+ /**
138
+ * Returns e.g `-05:00` for New_York winter time.
139
+ */
140
+ getUTCOffsetString(tz: string): string {
141
+ const minutes = this.getUTCOffsetMinutes(tz)
142
+ const hours = Math.trunc(minutes / 60)
143
+ const sign = hours < 0 ? '-' : '+'
144
+ const h = String(Math.abs(hours)).padStart(2, '0')
145
+ const m = String(minutes % 60).padStart(2, '0')
146
+ return `${sign}${h}:${m}`
147
+ }
148
+
71
149
  get(unit: LocalTimeUnit): number {
72
150
  if (unit === 'year') {
73
151
  return this.$date.getFullYear()
@@ -166,7 +244,7 @@ export class LocalTime {
166
244
  return v === undefined ? this.get('second') : this.set('second', v)
167
245
  }
168
246
 
169
- setComponents(c: Partial<LocalTimeComponents>, mutate = false): LocalTime {
247
+ setComponents(c: Partial<DateTimeObject>, mutate = false): LocalTime {
170
248
  const d = mutate ? this.$date : new Date(this.$date)
171
249
 
172
250
  // Year, month and day set all-at-once, to avoid 30/31 (and 28/29) mishap
@@ -422,6 +500,28 @@ export class LocalTime {
422
500
  return this.isSameOrAfter(localTime.of(now ?? new Date()).plus(-n, unit))
423
501
  }
424
502
 
503
+ getAgeInYears(now?: LocalTimeInput): number {
504
+ return this.getAgeIn('year', now)
505
+ }
506
+ getAgeInMonths(now?: LocalTimeInput): number {
507
+ return this.getAgeIn('month', now)
508
+ }
509
+ getAgeInDays(now?: LocalTimeInput): number {
510
+ return this.getAgeIn('day', now)
511
+ }
512
+ getAgeInHours(now?: LocalTimeInput): number {
513
+ return this.getAgeIn('hour', now)
514
+ }
515
+ getAgeInMinutes(now?: LocalTimeInput): number {
516
+ return this.getAgeIn('minute', now)
517
+ }
518
+ getAgeInSeconds(now?: LocalTimeInput): number {
519
+ return this.getAgeIn('second', now)
520
+ }
521
+ getAgeIn(unit: LocalTimeUnit, now?: LocalTimeInput): number {
522
+ return localTime.of(now ?? new Date()).diff(this, unit)
523
+ }
524
+
425
525
  /**
426
526
  * Returns 1 if this > d
427
527
  * returns 0 if they are equal
@@ -434,14 +534,14 @@ export class LocalTime {
434
534
  return t1 < t2 ? -1 : 1
435
535
  }
436
536
 
437
- components(): LocalTimeComponents {
537
+ getDateTimeObject(): DateTimeObject {
438
538
  return {
439
- ...this.dateComponents(),
440
- ...this.timeComponents(),
539
+ ...this.getDateObject(),
540
+ ...this.getTimeObject(),
441
541
  }
442
542
  }
443
543
 
444
- private dateComponents(): DateComponents {
544
+ getDateObject(): DateObject {
445
545
  return {
446
546
  year: this.$date.getFullYear(),
447
547
  month: this.$date.getMonth() + 1,
@@ -449,7 +549,7 @@ export class LocalTime {
449
549
  }
450
550
  }
451
551
 
452
- private timeComponents(): TimeComponents {
552
+ getTimeObject(): TimeObject {
453
553
  return {
454
554
  hour: this.$date.getHours(),
455
555
  minute: this.$date.getMinutes(),
@@ -518,7 +618,7 @@ export class LocalTime {
518
618
  * Returns e.g: `1984-06-21`, only the date part of DateTime
519
619
  */
520
620
  toISODate(): IsoDateString {
521
- const { year, month, day } = this.dateComponents()
621
+ const { year, month, day } = this.getDateObject()
522
622
 
523
623
  return [
524
624
  String(year).padStart(4, '0'),
@@ -534,7 +634,7 @@ export class LocalTime {
534
634
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
535
635
  */
536
636
  toISOTime(seconds = true): string {
537
- const { hour, minute, second } = this.timeComponents()
637
+ const { hour, minute, second } = this.getTimeObject()
538
638
 
539
639
  return [
540
640
  String(hour).padStart(2, '0'),
@@ -552,7 +652,7 @@ export class LocalTime {
552
652
  * Returns e.g: `19840621_1705`
553
653
  */
554
654
  toStringCompact(seconds = false): string {
555
- const { year, month, day, hour, minute, second } = this.components()
655
+ const { year, month, day, hour, minute, second } = this.getDateTimeObject()
556
656
 
557
657
  return [
558
658
  String(year).padStart(4, '0'),
@@ -672,6 +772,25 @@ class LocalTimeFactory {
672
772
  return this.parseOrNull(d) !== null
673
773
  }
674
774
 
775
+ /**
776
+ * Returns the IANA timezone e.g `Europe/Stockholm`.
777
+ * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
778
+ */
779
+ getTimezone(): string {
780
+ return Intl.DateTimeFormat().resolvedOptions().timeZone
781
+ }
782
+
783
+ /**
784
+ * Returns true if passed IANA timezone is valid/supported.
785
+ * E.g `Europe/Stockholm` is valid, but `Europe/Stockholm2` is not.
786
+ *
787
+ * This implementation is not optimized for performance. If you need frequent validation -
788
+ * consider caching the Intl.supportedValuesOf values as Set and reuse that.
789
+ */
790
+ isTimezoneValid(tz: string): boolean {
791
+ return Intl.supportedValuesOf('timeZone').includes(tz)
792
+ }
793
+
675
794
  now(): LocalTime {
676
795
  return new LocalTime(new Date())
677
796
  }
@@ -692,7 +811,7 @@ class LocalTimeFactory {
692
811
  return d ? this.of(d) : this.now()
693
812
  }
694
813
 
695
- fromComponents(c: { year: number; month: number } & Partial<LocalTimeComponents>): LocalTime {
814
+ fromComponents(c: { year: number; month: number } & Partial<DateTimeObject>): LocalTime {
696
815
  return new LocalTime(
697
816
  new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0),
698
817
  )
@@ -857,27 +976,3 @@ Object.setPrototypeOf(localTime, localTimeFactory)
857
976
  export function nowUnix(): UnixTimestampNumber {
858
977
  return Math.floor(Date.now() / 1000)
859
978
  }
860
-
861
- /**
862
- * UTC offset is the opposite of "timezone offset" - it's the number of minutes to add
863
- * to the local time to get UTC time.
864
- *
865
- * E.g utcOffset for CEST is -120,
866
- * which means that you need to add -120 minutes to the local time to get UTC time.
867
- *
868
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
869
- */
870
- export function getUTCOffsetMinutes(): NumberOfMinutes {
871
- return -new Date().getTimezoneOffset() || 0
872
- }
873
-
874
- /**
875
- * Same as getUTCOffsetMinutes, but rounded to hours.
876
- *
877
- * E.g for CEST it is -2.
878
- *
879
- * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
880
- */
881
- export function getUTCOffsetHours(): NumberOfHours {
882
- return Math.round(getUTCOffsetMinutes() / 60)
883
- }
@@ -0,0 +1,56 @@
1
+ import { DateTimeObject } from './localTime'
2
+
3
+ /**
4
+ * Representation of a "time on the wall clock",
5
+ * which means "local time, regardless of timezone".
6
+ *
7
+ * Experimental simplified container object to hold
8
+ * date and time components as numbers.
9
+ * No math or manipulation is possible here.
10
+ * Can be pretty-printed as Date, Time or DateAndTime.
11
+ */
12
+ export class WallTime implements DateTimeObject {
13
+ year!: number
14
+ month!: number
15
+ day!: number
16
+ hour!: number
17
+ minute!: number
18
+ second!: number
19
+
20
+ constructor(obj: DateTimeObject) {
21
+ Object.assign(this, obj)
22
+ }
23
+
24
+ /**
25
+ * Returns e.g: `1984-06-21 17:56:21`
26
+ * or (if seconds=false):
27
+ * `1984-06-21 17:56`
28
+ */
29
+ toPretty(seconds = true): string {
30
+ return this.toISODate() + ' ' + this.toISOTime(seconds)
31
+ }
32
+
33
+ /**
34
+ * Returns e.g: `1984-06-21`, only the date part of DateTime
35
+ */
36
+ toISODate(): string {
37
+ return [
38
+ String(this.year).padStart(4, '0'),
39
+ String(this.month).padStart(2, '0'),
40
+ String(this.day).padStart(2, '0'),
41
+ ].join('-')
42
+ }
43
+
44
+ /**
45
+ * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
46
+ */
47
+ toISOTime(seconds = true): string {
48
+ return [
49
+ String(this.hour).padStart(2, '0'),
50
+ String(this.minute).padStart(2, '0'),
51
+ seconds && String(this.second).padStart(2, '0'),
52
+ ]
53
+ .filter(Boolean)
54
+ .join(':')
55
+ }
56
+ }
package/src/index.ts CHANGED
@@ -26,7 +26,6 @@ export * from './json-schema/jsonSchema.cnst'
26
26
  export * from './json-schema/jsonSchema.model'
27
27
  export * from './json-schema/jsonSchema.util'
28
28
  export * from './json-schema/jsonSchemaBuilder'
29
- export * from './json-schema/jsonSchemaBuilder'
30
29
  export * from './math/math.util'
31
30
  export * from './math/sma'
32
31
  export * from './number/createDeterministicRandom'
@@ -68,10 +67,7 @@ export * from './math/stack.util'
68
67
  export * from './string/leven'
69
68
  export * from './datetime/localDate'
70
69
  export * from './datetime/localTime'
71
- export * from './datetime/dateInterval'
72
- export * from './datetime/timeInterval'
73
- export * from './datetime/localDate'
74
- export * from './datetime/localTime'
70
+ export * from './datetime/wallTime'
75
71
  export * from './datetime/dateInterval'
76
72
  export * from './datetime/timeInterval'
77
73
  export * from './env'