@naturalcycles/js-lib 14.230.0 → 14.231.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.
@@ -113,12 +113,21 @@ export declare class LocalDate {
113
113
  * Timezone will match local timezone.
114
114
  */
115
115
  toDate(): Date;
116
+ /**
117
+ * Converts LocalDate to Date in UTC timezone.
118
+ * Unlike normal `.toDate` that uses browser's timezone by default.
119
+ */
120
+ toDateInUTC(): Date;
116
121
  toLocalTime(): LocalTime;
117
122
  toISODate(): IsoDateString;
118
123
  /**
119
124
  * Returns e.g: `1984-06-21T17:56:21`
120
125
  */
121
126
  toISODateTime(): IsoDateTimeString;
127
+ /**
128
+ * Returns e.g: `1984-06-21T17:56:21Z` (notice the Z at the end, which indicates UTC)
129
+ */
130
+ toISODateTimeUTC(): IsoDateTimeString;
122
131
  toString(): IsoDateString;
123
132
  toStringCompact(): string;
124
133
  toMonthId(): MonthId;
@@ -153,4 +162,4 @@ export declare function localDateOrToday(d?: LocalDateInput | null): LocalDate;
153
162
  /**
154
163
  Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
155
164
  */
156
- export declare function todayIsoDateString(): IsoDateString;
165
+ export declare function todayString(): IsoDateString;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.todayIsoDateString = exports.localDateOrToday = exports.localDateOrUndefined = exports.localDateToday = exports.localDate = exports.localDateRangeIterable = exports.localDateRange = exports.LocalDate = void 0;
3
+ exports.todayString = exports.localDateOrToday = exports.localDateOrUndefined = exports.localDateToday = exports.localDate = exports.localDateRangeIterable = exports.localDateRange = exports.LocalDate = void 0;
4
4
  const assert_1 = require("../error/assert");
5
5
  const iterable2_1 = require("../iter/iterable2");
6
6
  const localTime_1 = require("./localTime");
@@ -51,7 +51,6 @@ class LocalDate {
51
51
  if (d instanceof Date) {
52
52
  return this.fromDate(d);
53
53
  }
54
- // const [year, month, day] = d.slice(0, 10).split('-').map(Number)
55
54
  const matches = typeof d === 'string' && DATE_REGEX.exec(d.slice(0, 10));
56
55
  if (!matches)
57
56
  return null;
@@ -69,10 +68,6 @@ class LocalDate {
69
68
  }
70
69
  return new LocalDate(year, month, day);
71
70
  }
72
- // Can use just .toString()
73
- // static parseToString(d: LocalDateConfig): IsoDateString {
74
- // return typeof d === 'string' ? d : d.toString()
75
- // }
76
71
  static isValid(iso) {
77
72
  return this.parseOrNull(iso) !== null;
78
73
  }
@@ -391,6 +386,13 @@ class LocalDate {
391
386
  toDate() {
392
387
  return new Date(this.$year, this.$month - 1, this.$day);
393
388
  }
389
+ /**
390
+ * Converts LocalDate to Date in UTC timezone.
391
+ * Unlike normal `.toDate` that uses browser's timezone by default.
392
+ */
393
+ toDateInUTC() {
394
+ return new Date(this.toISODateTimeUTC());
395
+ }
394
396
  toLocalTime() {
395
397
  return localTime_1.LocalTime.of(this.toDate());
396
398
  }
@@ -403,6 +405,12 @@ class LocalDate {
403
405
  toISODateTime() {
404
406
  return this.toString() + 'T00:00:00';
405
407
  }
408
+ /**
409
+ * Returns e.g: `1984-06-21T17:56:21Z` (notice the Z at the end, which indicates UTC)
410
+ */
411
+ toISODateTimeUTC() {
412
+ return this.toISODateTime() + 'Z';
413
+ }
406
414
  toString() {
407
415
  return [
408
416
  String(this.$year).padStart(4, '0'),
@@ -506,8 +514,10 @@ exports.localDateOrToday = localDateOrToday;
506
514
  /**
507
515
  Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
508
516
  */
509
- function todayIsoDateString() {
517
+ function todayString() {
510
518
  // It was benchmarked to be faster than by concatenating individual Date components
511
- return new Date().toISOString().slice(0, 10);
519
+ // return new Date().toISOString().slice(0, 10)
520
+ // But, toISOString always returns the date in UTC, so in the Browser it would give unexpected result!
521
+ return LocalDate.fromDate(new Date()).toString();
512
522
  }
513
- exports.todayIsoDateString = todayIsoDateString;
523
+ exports.todayString = todayString;
@@ -12,10 +12,13 @@ export declare enum ISODayOfWeek {
12
12
  }
13
13
  export type LocalTimeInput = LocalTime | Date | IsoDateTimeString | UnixTimestampNumber;
14
14
  export type LocalTimeFormatter = (ld: LocalTime) => string;
15
- export interface LocalTimeComponents {
15
+ export type LocalTimeComponents = DateComponents & TimeComponents;
16
+ interface DateComponents {
16
17
  year: number;
17
18
  month: number;
18
19
  day: number;
20
+ }
21
+ interface TimeComponents {
19
22
  hour: number;
20
23
  minute: number;
21
24
  second: number;
@@ -47,6 +50,7 @@ export declare class LocalTime {
47
50
  year: number;
48
51
  month: number;
49
52
  } & Partial<LocalTimeComponents>): LocalTime;
53
+ static fromDateUTC(d: Date): LocalTime;
50
54
  get(unit: LocalTimeUnit): number;
51
55
  set(unit: LocalTimeUnit, v: number, mutate?: boolean): LocalTime;
52
56
  year(): number;
@@ -126,6 +130,8 @@ export declare class LocalTime {
126
130
  */
127
131
  cmp(d: LocalTimeInput): -1 | 0 | 1;
128
132
  components(): LocalTimeComponents;
133
+ private dateComponents;
134
+ private timeComponents;
129
135
  fromNow(now?: LocalTimeInput): string;
130
136
  getDate(): Date;
131
137
  clone(): LocalTime;
@@ -133,6 +139,11 @@ export declare class LocalTime {
133
139
  unixMillis(): UnixTimestampMillisNumber;
134
140
  valueOf(): UnixTimestampNumber;
135
141
  toLocalDate(): LocalDate;
142
+ /**
143
+ * Returns e.g: `1984-06-21 17:56:21`
144
+ * or (if seconds=false):
145
+ * `1984-06-21 17:56`
146
+ */
136
147
  toPretty(seconds?: boolean): IsoDateTimeString;
137
148
  /**
138
149
  * Returns e.g: `1984-06-21T17:56:21`
@@ -196,3 +207,4 @@ export declare function getUTCOffsetMinutes(): NumberOfMinutes;
196
207
  * Instead of -0 it returns 0, for the peace of mind and less weird test/snapshot differences.
197
208
  */
198
209
  export declare function getUTCOffsetHours(): NumberOfHours;
210
+ export {};
@@ -64,7 +64,12 @@ class LocalTime {
64
64
  return null;
65
65
  }
66
66
  else {
67
+ // Slicing removes the "timezone component", and makes the date "local"
68
+ // e.g 2022-04-06T23:15:00+09:00
69
+ // becomes 2022-04-06T23:15:00
67
70
  date = new Date(d.slice(0, 19));
71
+ // We used to slice to remove the timezone information, now we don't
72
+ // date = new Date(d)
68
73
  }
69
74
  // validation
70
75
  if (isNaN(date.getDate())) {
@@ -107,6 +112,9 @@ class LocalTime {
107
112
  static fromComponents(c) {
108
113
  return new LocalTime(new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0));
109
114
  }
115
+ static fromDateUTC(d) {
116
+ return new LocalTime(new Date(d.toISOString()));
117
+ }
110
118
  get(unit) {
111
119
  if (unit === 'year') {
112
120
  return this.$date.getFullYear();
@@ -422,6 +430,20 @@ class LocalTime {
422
430
  second: this.$date.getSeconds(),
423
431
  };
424
432
  }
433
+ dateComponents() {
434
+ return {
435
+ year: this.$date.getFullYear(),
436
+ month: this.$date.getMonth() + 1,
437
+ day: this.$date.getDate(),
438
+ };
439
+ }
440
+ timeComponents() {
441
+ return {
442
+ hour: this.$date.getHours(),
443
+ minute: this.$date.getMinutes(),
444
+ second: this.$date.getSeconds(),
445
+ };
446
+ }
425
447
  fromNow(now = new Date()) {
426
448
  const msDiff = LocalTime.parseToDate(now).valueOf() - this.$date.valueOf();
427
449
  if (msDiff === 0)
@@ -449,27 +471,52 @@ class LocalTime {
449
471
  toLocalDate() {
450
472
  return localDate_1.LocalDate.fromDate(this.$date);
451
473
  }
474
+ /**
475
+ * Returns e.g: `1984-06-21 17:56:21`
476
+ * or (if seconds=false):
477
+ * `1984-06-21 17:56`
478
+ */
452
479
  toPretty(seconds = true) {
453
- const s = this.$date.toISOString();
454
- return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16);
480
+ return this.toISODate() + ' ' + this.toISOTime(seconds);
481
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
482
+ // const s = this.$date.toISOString()
483
+ // return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16)
455
484
  }
456
485
  /**
457
486
  * Returns e.g: `1984-06-21T17:56:21`
458
487
  */
459
488
  toISODateTime() {
460
- return this.$date.toISOString().slice(0, 19);
489
+ return this.toISODate() + 'T' + this.toISOTime();
490
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
491
+ // return this.$date.toISOString().slice(0, 19)
461
492
  }
462
493
  /**
463
494
  * Returns e.g: `1984-06-21`, only the date part of DateTime
464
495
  */
465
496
  toISODate() {
466
- return this.$date.toISOString().slice(0, 10);
497
+ const { year, month, day } = this.dateComponents();
498
+ return [
499
+ String(year).padStart(4, '0'),
500
+ String(month).padStart(2, '0'),
501
+ String(day).padStart(2, '0'),
502
+ ].join('-');
503
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
504
+ // return this.$date.toISOString().slice(0, 10)
467
505
  }
468
506
  /**
469
507
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
470
508
  */
471
509
  toISOTime(seconds = true) {
472
- return this.$date.toISOString().slice(11, seconds ? 19 : 16);
510
+ const { hour, minute, second } = this.timeComponents();
511
+ return [
512
+ String(hour).padStart(2, '0'),
513
+ String(minute).padStart(2, '0'),
514
+ seconds && String(second).padStart(2, '0'),
515
+ ]
516
+ .filter(Boolean)
517
+ .join(':');
518
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
519
+ // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
473
520
  }
474
521
  /**
475
522
  * Returns e.g: `19840621_1705`
@@ -493,7 +540,7 @@ class LocalTime {
493
540
  return this.unix();
494
541
  }
495
542
  toMonthId() {
496
- return this.$date.toISOString().slice(0, 7);
543
+ return this.toISODate().slice(0, 7);
497
544
  }
498
545
  format(fmt) {
499
546
  if (fmt instanceof Intl.DateTimeFormat) {
@@ -48,7 +48,6 @@ export class LocalDate {
48
48
  if (d instanceof Date) {
49
49
  return this.fromDate(d);
50
50
  }
51
- // const [year, month, day] = d.slice(0, 10).split('-').map(Number)
52
51
  const matches = typeof d === 'string' && DATE_REGEX.exec(d.slice(0, 10));
53
52
  if (!matches)
54
53
  return null;
@@ -66,10 +65,6 @@ export class LocalDate {
66
65
  }
67
66
  return new LocalDate(year, month, day);
68
67
  }
69
- // Can use just .toString()
70
- // static parseToString(d: LocalDateConfig): IsoDateString {
71
- // return typeof d === 'string' ? d : d.toString()
72
- // }
73
68
  static isValid(iso) {
74
69
  return this.parseOrNull(iso) !== null;
75
70
  }
@@ -388,6 +383,13 @@ export class LocalDate {
388
383
  toDate() {
389
384
  return new Date(this.$year, this.$month - 1, this.$day);
390
385
  }
386
+ /**
387
+ * Converts LocalDate to Date in UTC timezone.
388
+ * Unlike normal `.toDate` that uses browser's timezone by default.
389
+ */
390
+ toDateInUTC() {
391
+ return new Date(this.toISODateTimeUTC());
392
+ }
391
393
  toLocalTime() {
392
394
  return LocalTime.of(this.toDate());
393
395
  }
@@ -400,6 +402,12 @@ export class LocalDate {
400
402
  toISODateTime() {
401
403
  return this.toString() + 'T00:00:00';
402
404
  }
405
+ /**
406
+ * Returns e.g: `1984-06-21T17:56:21Z` (notice the Z at the end, which indicates UTC)
407
+ */
408
+ toISODateTimeUTC() {
409
+ return this.toISODateTime() + 'Z';
410
+ }
403
411
  toString() {
404
412
  return [
405
413
  String(this.$year).padStart(4, '0'),
@@ -496,7 +504,9 @@ export function localDateOrToday(d) {
496
504
  /**
497
505
  Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
498
506
  */
499
- export function todayIsoDateString() {
507
+ export function todayString() {
500
508
  // It was benchmarked to be faster than by concatenating individual Date components
501
- return new Date().toISOString().slice(0, 10);
509
+ // return new Date().toISOString().slice(0, 10)
510
+ // But, toISOString always returns the date in UTC, so in the Browser it would give unexpected result!
511
+ return LocalDate.fromDate(new Date()).toString();
502
512
  }
@@ -61,7 +61,12 @@ export class LocalTime {
61
61
  return null;
62
62
  }
63
63
  else {
64
+ // Slicing removes the "timezone component", and makes the date "local"
65
+ // e.g 2022-04-06T23:15:00+09:00
66
+ // becomes 2022-04-06T23:15:00
64
67
  date = new Date(d.slice(0, 19));
68
+ // We used to slice to remove the timezone information, now we don't
69
+ // date = new Date(d)
65
70
  }
66
71
  // validation
67
72
  if (isNaN(date.getDate())) {
@@ -104,6 +109,9 @@ export class LocalTime {
104
109
  static fromComponents(c) {
105
110
  return new LocalTime(new Date(c.year, c.month - 1, c.day || 1, c.hour || 0, c.minute || 0, c.second || 0));
106
111
  }
112
+ static fromDateUTC(d) {
113
+ return new LocalTime(new Date(d.toISOString()));
114
+ }
107
115
  get(unit) {
108
116
  if (unit === 'year') {
109
117
  return this.$date.getFullYear();
@@ -420,6 +428,20 @@ export class LocalTime {
420
428
  second: this.$date.getSeconds(),
421
429
  };
422
430
  }
431
+ dateComponents() {
432
+ return {
433
+ year: this.$date.getFullYear(),
434
+ month: this.$date.getMonth() + 1,
435
+ day: this.$date.getDate(),
436
+ };
437
+ }
438
+ timeComponents() {
439
+ return {
440
+ hour: this.$date.getHours(),
441
+ minute: this.$date.getMinutes(),
442
+ second: this.$date.getSeconds(),
443
+ };
444
+ }
423
445
  fromNow(now = new Date()) {
424
446
  const msDiff = LocalTime.parseToDate(now).valueOf() - this.$date.valueOf();
425
447
  if (msDiff === 0)
@@ -447,27 +469,52 @@ export class LocalTime {
447
469
  toLocalDate() {
448
470
  return LocalDate.fromDate(this.$date);
449
471
  }
472
+ /**
473
+ * Returns e.g: `1984-06-21 17:56:21`
474
+ * or (if seconds=false):
475
+ * `1984-06-21 17:56`
476
+ */
450
477
  toPretty(seconds = true) {
451
- const s = this.$date.toISOString();
452
- return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16);
478
+ return this.toISODate() + ' ' + this.toISOTime(seconds);
479
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
480
+ // const s = this.$date.toISOString()
481
+ // return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16)
453
482
  }
454
483
  /**
455
484
  * Returns e.g: `1984-06-21T17:56:21`
456
485
  */
457
486
  toISODateTime() {
458
- return this.$date.toISOString().slice(0, 19);
487
+ return this.toISODate() + 'T' + this.toISOTime();
488
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
489
+ // return this.$date.toISOString().slice(0, 19)
459
490
  }
460
491
  /**
461
492
  * Returns e.g: `1984-06-21`, only the date part of DateTime
462
493
  */
463
494
  toISODate() {
464
- return this.$date.toISOString().slice(0, 10);
495
+ const { year, month, day } = this.dateComponents();
496
+ return [
497
+ String(year).padStart(4, '0'),
498
+ String(month).padStart(2, '0'),
499
+ String(day).padStart(2, '0'),
500
+ ].join('-');
501
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
502
+ // return this.$date.toISOString().slice(0, 10)
465
503
  }
466
504
  /**
467
505
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
468
506
  */
469
507
  toISOTime(seconds = true) {
470
- return this.$date.toISOString().slice(11, seconds ? 19 : 16);
508
+ const { hour, minute, second } = this.timeComponents();
509
+ return [
510
+ String(hour).padStart(2, '0'),
511
+ String(minute).padStart(2, '0'),
512
+ seconds && String(second).padStart(2, '0'),
513
+ ]
514
+ .filter(Boolean)
515
+ .join(':');
516
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
517
+ // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
471
518
  }
472
519
  /**
473
520
  * Returns e.g: `19840621_1705`
@@ -491,7 +538,7 @@ export class LocalTime {
491
538
  return this.unix();
492
539
  }
493
540
  toMonthId() {
494
- return this.$date.toISOString().slice(0, 7);
541
+ return this.toISODate().slice(0, 7);
495
542
  }
496
543
  format(fmt) {
497
544
  if (fmt instanceof Intl.DateTimeFormat) {
package/package.json CHANGED
@@ -1,9 +1,11 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.230.0",
3
+ "version": "14.231.0",
4
4
  "scripts": {
5
5
  "prepare": "husky",
6
6
  "build-prod": "build-prod-esm-cjs",
7
+ "test-tz1": "TZ=Europe/Stockholm test local",
8
+ "test-tz2": "TZ=JST-9 test local",
7
9
  "docs-dev": "vitepress dev docs --open",
8
10
  "docs-build": "vitepress build docs",
9
11
  "docs-preview": "vitepress preview docs"
@@ -74,7 +74,6 @@ export class LocalDate {
74
74
  return this.fromDate(d)
75
75
  }
76
76
 
77
- // const [year, month, day] = d.slice(0, 10).split('-').map(Number)
78
77
  const matches = typeof (d as any) === 'string' && DATE_REGEX.exec(d.slice(0, 10))
79
78
  if (!matches) return null
80
79
 
@@ -97,11 +96,6 @@ export class LocalDate {
97
96
  return new LocalDate(year, month, day)
98
97
  }
99
98
 
100
- // Can use just .toString()
101
- // static parseToString(d: LocalDateConfig): IsoDateString {
102
- // return typeof d === 'string' ? d : d.toString()
103
- // }
104
-
105
99
  static isValid(iso: string | undefined | null): boolean {
106
100
  return this.parseOrNull(iso) !== null
107
101
  }
@@ -473,6 +467,14 @@ export class LocalDate {
473
467
  return new Date(this.$year, this.$month - 1, this.$day)
474
468
  }
475
469
 
470
+ /**
471
+ * Converts LocalDate to Date in UTC timezone.
472
+ * Unlike normal `.toDate` that uses browser's timezone by default.
473
+ */
474
+ toDateInUTC(): Date {
475
+ return new Date(this.toISODateTimeUTC())
476
+ }
477
+
476
478
  toLocalTime(): LocalTime {
477
479
  return LocalTime.of(this.toDate())
478
480
  }
@@ -488,6 +490,13 @@ export class LocalDate {
488
490
  return this.toString() + 'T00:00:00'
489
491
  }
490
492
 
493
+ /**
494
+ * Returns e.g: `1984-06-21T17:56:21Z` (notice the Z at the end, which indicates UTC)
495
+ */
496
+ toISODateTimeUTC(): IsoDateTimeString {
497
+ return this.toISODateTime() + 'Z'
498
+ }
499
+
491
500
  toString(): IsoDateString {
492
501
  return [
493
502
  String(this.$year).padStart(4, '0'),
@@ -614,7 +623,9 @@ export function localDateOrToday(d?: LocalDateInput | null): LocalDate {
614
623
  /**
615
624
  Convenience function to return current today's IsoDateString representation, e.g `2024-06-21`
616
625
  */
617
- export function todayIsoDateString(): IsoDateString {
626
+ export function todayString(): IsoDateString {
618
627
  // It was benchmarked to be faster than by concatenating individual Date components
619
- return new Date().toISOString().slice(0, 10)
628
+ // return new Date().toISOString().slice(0, 10)
629
+ // But, toISOString always returns the date in UTC, so in the Browser it would give unexpected result!
630
+ return LocalDate.fromDate(new Date()).toString()
620
631
  }
@@ -28,10 +28,15 @@ export enum ISODayOfWeek {
28
28
  export type LocalTimeInput = LocalTime | Date | IsoDateTimeString | UnixTimestampNumber
29
29
  export type LocalTimeFormatter = (ld: LocalTime) => string
30
30
 
31
- export interface LocalTimeComponents {
31
+ export type LocalTimeComponents = DateComponents & TimeComponents
32
+
33
+ interface DateComponents {
32
34
  year: number
33
35
  month: number
34
36
  day: number
37
+ }
38
+
39
+ interface TimeComponents {
35
40
  hour: number
36
41
  minute: number
37
42
  second: number
@@ -88,7 +93,12 @@ export class LocalTime {
88
93
  // unexpected type, e.g Function or something
89
94
  return null
90
95
  } else {
96
+ // Slicing removes the "timezone component", and makes the date "local"
97
+ // e.g 2022-04-06T23:15:00+09:00
98
+ // becomes 2022-04-06T23:15:00
91
99
  date = new Date(d.slice(0, 19))
100
+ // We used to slice to remove the timezone information, now we don't
101
+ // date = new Date(d)
92
102
  }
93
103
 
94
104
  // validation
@@ -146,6 +156,10 @@ export class LocalTime {
146
156
  )
147
157
  }
148
158
 
159
+ static fromDateUTC(d: Date): LocalTime {
160
+ return new LocalTime(new Date(d.toISOString()))
161
+ }
162
+
149
163
  get(unit: LocalTimeUnit): number {
150
164
  if (unit === 'year') {
151
165
  return this.$date.getFullYear()
@@ -514,6 +528,22 @@ export class LocalTime {
514
528
  }
515
529
  }
516
530
 
531
+ private dateComponents(): DateComponents {
532
+ return {
533
+ year: this.$date.getFullYear(),
534
+ month: this.$date.getMonth() + 1,
535
+ day: this.$date.getDate(),
536
+ }
537
+ }
538
+
539
+ private timeComponents(): TimeComponents {
540
+ return {
541
+ hour: this.$date.getHours(),
542
+ minute: this.$date.getMinutes(),
543
+ second: this.$date.getSeconds(),
544
+ }
545
+ }
546
+
517
547
  fromNow(now: LocalTimeInput = new Date()): string {
518
548
  const msDiff = LocalTime.parseToDate(now).valueOf() - this.$date.valueOf()
519
549
 
@@ -550,30 +580,59 @@ export class LocalTime {
550
580
  return LocalDate.fromDate(this.$date)
551
581
  }
552
582
 
583
+ /**
584
+ * Returns e.g: `1984-06-21 17:56:21`
585
+ * or (if seconds=false):
586
+ * `1984-06-21 17:56`
587
+ */
553
588
  toPretty(seconds = true): IsoDateTimeString {
554
- const s = this.$date.toISOString()
555
- return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16)
589
+ return this.toISODate() + ' ' + this.toISOTime(seconds)
590
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
591
+ // const s = this.$date.toISOString()
592
+ // return s.slice(0, 10) + ' ' + s.slice(11, seconds ? 19 : 16)
556
593
  }
557
594
 
558
595
  /**
559
596
  * Returns e.g: `1984-06-21T17:56:21`
560
597
  */
561
598
  toISODateTime(): IsoDateTimeString {
562
- return this.$date.toISOString().slice(0, 19)
599
+ return this.toISODate() + 'T' + this.toISOTime()
600
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
601
+ // return this.$date.toISOString().slice(0, 19)
563
602
  }
564
603
 
565
604
  /**
566
605
  * Returns e.g: `1984-06-21`, only the date part of DateTime
567
606
  */
568
607
  toISODate(): IsoDateString {
569
- return this.$date.toISOString().slice(0, 10)
608
+ const { year, month, day } = this.dateComponents()
609
+
610
+ return [
611
+ String(year).padStart(4, '0'),
612
+ String(month).padStart(2, '0'),
613
+ String(day).padStart(2, '0'),
614
+ ].join('-')
615
+
616
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
617
+ // return this.$date.toISOString().slice(0, 10)
570
618
  }
571
619
 
572
620
  /**
573
621
  * Returns e.g: `17:03:15` (or `17:03` with seconds=false)
574
622
  */
575
623
  toISOTime(seconds = true): string {
576
- return this.$date.toISOString().slice(11, seconds ? 19 : 16)
624
+ const { hour, minute, second } = this.timeComponents()
625
+
626
+ return [
627
+ String(hour).padStart(2, '0'),
628
+ String(minute).padStart(2, '0'),
629
+ seconds && String(second).padStart(2, '0'),
630
+ ]
631
+ .filter(Boolean)
632
+ .join(':')
633
+
634
+ // !! Not using toISOString(), as it returns time in UTC, not in local timezone (unexpected!)
635
+ // return this.$date.toISOString().slice(11, seconds ? 19 : 16)
577
636
  }
578
637
 
579
638
  /**
@@ -602,7 +661,7 @@ export class LocalTime {
602
661
  }
603
662
 
604
663
  toMonthId(): MonthId {
605
- return this.$date.toISOString().slice(0, 7)
664
+ return this.toISODate().slice(0, 7)
606
665
  }
607
666
 
608
667
  format(fmt: Intl.DateTimeFormat | LocalTimeFormatter): string {