@timestamp-js/core 0.1.0-alpha.2 → 0.1.0-beta.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.
- package/README.md +2 -0
- package/dist/index.d.ts +594 -312
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +743 -297
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.js
CHANGED
|
@@ -97,6 +97,10 @@ export const HOURS_IN_DAY = TIME_CONSTANTS.HOURS_IN.DAY;
|
|
|
97
97
|
* Number of milliseconds in one minute.
|
|
98
98
|
*/
|
|
99
99
|
export const MILLISECONDS_IN_MINUTE = TIME_CONSTANTS.MILLISECONDS_IN.MINUTE;
|
|
100
|
+
/**
|
|
101
|
+
* Number of milliseconds in one second.
|
|
102
|
+
*/
|
|
103
|
+
export const MILLISECONDS_IN_SECOND = TIME_CONSTANTS.MILLISECONDS_IN.SECOND;
|
|
100
104
|
/**
|
|
101
105
|
* Number of milliseconds in one hour.
|
|
102
106
|
*/
|
|
@@ -109,10 +113,22 @@ export const MILLISECONDS_IN_DAY = TIME_CONSTANTS.MILLISECONDS_IN.DAY;
|
|
|
109
113
|
* Number of milliseconds in one week.
|
|
110
114
|
*/
|
|
111
115
|
export const MILLISECONDS_IN_WEEK = TIME_CONSTANTS.MILLISECONDS_IN.WEEK;
|
|
116
|
+
/**
|
|
117
|
+
* Number of seconds in one minute.
|
|
118
|
+
*/
|
|
119
|
+
export const SECONDS_IN_MINUTE = TIME_CONSTANTS.SECONDS_IN.MINUTE;
|
|
120
|
+
/**
|
|
121
|
+
* Number of seconds in one hour.
|
|
122
|
+
*/
|
|
123
|
+
export const SECONDS_IN_HOUR = TIME_CONSTANTS.SECONDS_IN.HOUR;
|
|
124
|
+
/**
|
|
125
|
+
* Number of seconds in one day.
|
|
126
|
+
*/
|
|
127
|
+
export const SECONDS_IN_DAY = TIME_CONSTANTS.SECONDS_IN.DAY;
|
|
112
128
|
/**
|
|
113
129
|
* Frozen empty timestamp template.
|
|
114
130
|
*
|
|
115
|
-
* Use
|
|
131
|
+
* Use copyTimestamp or parser helpers to create new timestamp objects
|
|
116
132
|
* instead of mutating this shared default.
|
|
117
133
|
*/
|
|
118
134
|
export const Timestamp = freezeTimestamp({
|
|
@@ -163,11 +179,11 @@ export function validateTimestamp(input) {
|
|
|
163
179
|
* Fast low-level parser for date and date-time strings.
|
|
164
180
|
*
|
|
165
181
|
* This parser fills numeric fields, but does not update formatted date,
|
|
166
|
-
* weekday, day-of-year, workweek, or relative flags. Use
|
|
167
|
-
*
|
|
182
|
+
* weekday, day-of-year, workweek, or relative flags. Use parseTimestamp()
|
|
183
|
+
* when those derived fields are needed.
|
|
168
184
|
*
|
|
169
185
|
* @param {string} input In the form `YYYY-MM-DD`, `YYYY-MM-DD HH:mm:ss`, or an ISO-like date time with optional milliseconds and timezone suffix.
|
|
170
|
-
* @returns {Timestamp}
|
|
186
|
+
* @returns {Timestamp} Minimal Timestamp object, or `null` when the input cannot be parsed.
|
|
171
187
|
*/
|
|
172
188
|
export function parsed(input) {
|
|
173
189
|
if (typeof input !== "string")
|
|
@@ -211,15 +227,11 @@ export function parsed(input) {
|
|
|
211
227
|
timestamp.time = getTime(timestamp);
|
|
212
228
|
return freezeTimestamp(timestamp);
|
|
213
229
|
}
|
|
214
|
-
|
|
215
|
-
* Takes a JavaScript Date and returns a {@link Timestamp}. The {@link Timestamp} is not updated with relative information.
|
|
216
|
-
* @param {Date} date JavaScript Date
|
|
217
|
-
* @param {boolean} utc If set the {@link Timestamp} will parse the Date as UTC
|
|
218
|
-
* @returns {Timestamp} A minimal {@link Timestamp} without updated or relative updates.
|
|
219
|
-
*/
|
|
220
|
-
export function parseDate(date, utc = false) {
|
|
230
|
+
function parseDateByMode(date, utc) {
|
|
221
231
|
if (!(date instanceof Date))
|
|
222
232
|
return null;
|
|
233
|
+
if (Number.isNaN(date.getTime()))
|
|
234
|
+
return null;
|
|
223
235
|
const UTC = utc ? "UTC" : "";
|
|
224
236
|
const second = date[`get${UTC}Seconds`]();
|
|
225
237
|
const millisecond = date[`get${UTC}Milliseconds`]();
|
|
@@ -255,6 +267,30 @@ export function parseDate(date, utc = false) {
|
|
|
255
267
|
}
|
|
256
268
|
return updateFormatted(timestamp);
|
|
257
269
|
}
|
|
270
|
+
/**
|
|
271
|
+
* Converts a JavaScript Date into a formatted Timestamp using host-local fields.
|
|
272
|
+
*
|
|
273
|
+
* Use parseDateUTC() when the Date represents an instant that should be read
|
|
274
|
+
* with UTC getters instead of host-local getters.
|
|
275
|
+
*
|
|
276
|
+
* @param {Date} date JavaScript Date to convert.
|
|
277
|
+
* @returns {Timestamp} Formatted Timestamp object, or `null` for invalid input.
|
|
278
|
+
*/
|
|
279
|
+
export function parseDate(date) {
|
|
280
|
+
return parseDateByMode(date, false);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Converts a JavaScript Date into a formatted Timestamp using UTC fields.
|
|
284
|
+
*
|
|
285
|
+
* Use this when server and client output should agree on the same UTC calendar
|
|
286
|
+
* and time fields for a native Date instant.
|
|
287
|
+
*
|
|
288
|
+
* @param {Date} date JavaScript Date to convert.
|
|
289
|
+
* @returns {Timestamp} Formatted Timestamp object, or `null` for invalid input.
|
|
290
|
+
*/
|
|
291
|
+
export function parseDateUTC(date) {
|
|
292
|
+
return parseDateByMode(date, true);
|
|
293
|
+
}
|
|
258
294
|
/**
|
|
259
295
|
* Pads a number to a requested string length.
|
|
260
296
|
*
|
|
@@ -290,9 +326,10 @@ export function daysInMonth(year, month) {
|
|
|
290
326
|
return (isLeapYear(year) ? DAYS_IN_MONTH_LEAP[month] : DAYS_IN_MONTH[month]);
|
|
291
327
|
}
|
|
292
328
|
/**
|
|
293
|
-
* Returns a
|
|
294
|
-
*
|
|
295
|
-
* @
|
|
329
|
+
* Returns a new Timestamp for the next calendar day.
|
|
330
|
+
*
|
|
331
|
+
* @param {Timestamp} timestamp Base Timestamp object.
|
|
332
|
+
* @returns {Timestamp} New Timestamp representing the next day.
|
|
296
333
|
*/
|
|
297
334
|
export function nextDay(timestamp) {
|
|
298
335
|
const date = new Date(timestamp.year, timestamp.month - 1, timestamp.day + 1);
|
|
@@ -304,9 +341,10 @@ export function nextDay(timestamp) {
|
|
|
304
341
|
}));
|
|
305
342
|
}
|
|
306
343
|
/**
|
|
307
|
-
* Returns a
|
|
308
|
-
*
|
|
309
|
-
* @
|
|
344
|
+
* Returns a new Timestamp for the previous calendar day.
|
|
345
|
+
*
|
|
346
|
+
* @param {Timestamp} timestamp Base Timestamp object.
|
|
347
|
+
* @returns {Timestamp} New Timestamp representing the previous day.
|
|
310
348
|
*/
|
|
311
349
|
export function prevDay(timestamp) {
|
|
312
350
|
const date = new Date(timestamp.year, timestamp.month - 1, timestamp.day - 1);
|
|
@@ -318,13 +356,48 @@ export function prevDay(timestamp) {
|
|
|
318
356
|
}));
|
|
319
357
|
}
|
|
320
358
|
/**
|
|
321
|
-
* Returns today's date
|
|
359
|
+
* Returns today's date using the host runtime timezone.
|
|
360
|
+
*
|
|
361
|
+
* For SSR or static rendering, server and client runtimes can produce different
|
|
362
|
+
* values when they run in different timezones. Use todayUTC() when the app
|
|
363
|
+
* wants a stable UTC calendar date instead.
|
|
364
|
+
*
|
|
322
365
|
* @returns {string} Date string in the form `YYYY-MM-DD`
|
|
323
366
|
*/
|
|
324
367
|
export function today() {
|
|
325
368
|
const d = new Date(), month = d.getMonth() + 1, day = d.getDate(), year = d.getFullYear();
|
|
326
369
|
return [year, padNumber(month, 2), padNumber(day, 2)].join("-");
|
|
327
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* Returns today's date using UTC calendar fields.
|
|
373
|
+
*
|
|
374
|
+
* Pass a Date fixture to make SSR, tests, and hydration-sensitive render paths
|
|
375
|
+
* deterministic. This helper reads UTC fields only; it does not convert an
|
|
376
|
+
* existing Timestamp or timezone-suffixed string.
|
|
377
|
+
*
|
|
378
|
+
* @param {Date} date Date source to read. Defaults to the current Date.
|
|
379
|
+
* @returns {string} UTC date string in the form `YYYY-MM-DD`
|
|
380
|
+
*/
|
|
381
|
+
export function todayUTC(date = new Date()) {
|
|
382
|
+
return [
|
|
383
|
+
padNumber(date.getUTCFullYear(), 4),
|
|
384
|
+
padNumber(date.getUTCMonth() + 1, 2),
|
|
385
|
+
padNumber(date.getUTCDate(), 2),
|
|
386
|
+
].join("-");
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Returns the current date-time as an immutable Timestamp using UTC fields.
|
|
390
|
+
*
|
|
391
|
+
* Use this when server and client output should agree on UTC calendar and time
|
|
392
|
+
* values. For fully deterministic SSR output, pass a Date captured by the
|
|
393
|
+
* caller instead of allowing each runtime to create its own current Date.
|
|
394
|
+
*
|
|
395
|
+
* @param {Date} date Date source to read. Defaults to the current Date.
|
|
396
|
+
* @returns {Timestamp} Immutable Timestamp built from UTC fields.
|
|
397
|
+
*/
|
|
398
|
+
export function nowUTC(date = new Date()) {
|
|
399
|
+
return parseDateUTC(date);
|
|
400
|
+
}
|
|
328
401
|
/**
|
|
329
402
|
* Takes a date string ('YYYY-MM-DD') and validates if it is today's date
|
|
330
403
|
* @param {string} date Date string in the form 'YYYY-MM-DD'
|
|
@@ -334,12 +407,25 @@ export function isToday(date) {
|
|
|
334
407
|
return date === today();
|
|
335
408
|
}
|
|
336
409
|
/**
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
410
|
+
* Checks whether a date string matches today's UTC date.
|
|
411
|
+
*
|
|
412
|
+
* Pass a Date fixture when SSR, tests, or hydration-sensitive render paths need
|
|
413
|
+
* deterministic behavior.
|
|
414
|
+
*
|
|
415
|
+
* @param {string} date Date string in the form `YYYY-MM-DD`.
|
|
416
|
+
* @param {Date} now Date source to read. Defaults to the current Date.
|
|
417
|
+
* @returns {boolean} True when the date matches the UTC date.
|
|
418
|
+
*/
|
|
419
|
+
export function isTodayUTC(date, now = new Date()) {
|
|
420
|
+
return date === todayUTC(now);
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Returns the start of the week for a Timestamp and weekday set.
|
|
424
|
+
* If a current Timestamp is provided, the returned Timestamp includes updated relative information.
|
|
425
|
+
* @param {Timestamp} timestamp The Timestamp to use to find the start of the week
|
|
340
426
|
* @param {number[]} weekdays The array is [0,1,2,3,4,5,6] where 0=Sunday and 6=Saturday
|
|
341
|
-
* @param {Timestamp=} today
|
|
342
|
-
* @returns {Timestamp} A new
|
|
427
|
+
* @param {Timestamp=} today Current timestamp used to update relative information
|
|
428
|
+
* @returns {Timestamp} A new Timestamp representing the start of the week
|
|
343
429
|
*/
|
|
344
430
|
export function getStartOfWeek(timestamp, weekdays, today) {
|
|
345
431
|
let start = cloneTimestamp(timestamp);
|
|
@@ -359,12 +445,12 @@ export function getStartOfWeek(timestamp, weekdays, today) {
|
|
|
359
445
|
return start;
|
|
360
446
|
}
|
|
361
447
|
/**
|
|
362
|
-
* Returns the end of the week
|
|
363
|
-
* If
|
|
364
|
-
* @param {Timestamp} timestamp The
|
|
448
|
+
* Returns the end of the week for a Timestamp and weekday set.
|
|
449
|
+
* If a current Timestamp is provided, the returned Timestamp includes updated relative information.
|
|
450
|
+
* @param {Timestamp} timestamp The Timestamp to use to find the end of the week
|
|
365
451
|
* @param {number[]} weekdays The array is [0,1,2,3,4,5,6] where 0=Sunday and 6=Saturday
|
|
366
|
-
* @param {Timestamp=} today
|
|
367
|
-
* @returns {Timestamp} A new
|
|
452
|
+
* @param {Timestamp=} today Current timestamp used to update relative information
|
|
453
|
+
* @returns {Timestamp} A new Timestamp representing the end of the week
|
|
368
454
|
*/
|
|
369
455
|
export function getEndOfWeek(timestamp, weekdays, today) {
|
|
370
456
|
let end = cloneTimestamp(timestamp);
|
|
@@ -386,9 +472,9 @@ export function getEndOfWeek(timestamp, weekdays, today) {
|
|
|
386
472
|
return end;
|
|
387
473
|
}
|
|
388
474
|
/**
|
|
389
|
-
* Finds the start of the month based on the passed in
|
|
390
|
-
* @param {Timestamp} timestamp The
|
|
391
|
-
* @returns {Timestamp} A
|
|
475
|
+
* Finds the start of the month based on the passed in Timestamp
|
|
476
|
+
* @param {Timestamp} timestamp The Timestamp to use to find the start of the month
|
|
477
|
+
* @returns {Timestamp} A Timestamp of the start of the month
|
|
392
478
|
*/
|
|
393
479
|
export function getStartOfMonth(timestamp) {
|
|
394
480
|
let start = cloneTimestamp(timestamp);
|
|
@@ -397,9 +483,9 @@ export function getStartOfMonth(timestamp) {
|
|
|
397
483
|
return start;
|
|
398
484
|
}
|
|
399
485
|
/**
|
|
400
|
-
* Finds the end of the month based on the passed in
|
|
401
|
-
* @param {Timestamp} timestamp The
|
|
402
|
-
* @returns {Timestamp} A
|
|
486
|
+
* Finds the end of the month based on the passed in Timestamp
|
|
487
|
+
* @param {Timestamp} timestamp The Timestamp to use to find the end of the month
|
|
488
|
+
* @returns {Timestamp} A Timestamp of the end of the month
|
|
403
489
|
*/
|
|
404
490
|
export function getEndOfMonth(timestamp) {
|
|
405
491
|
let end = cloneTimestamp(timestamp);
|
|
@@ -445,10 +531,11 @@ export function parseTime(input) {
|
|
|
445
531
|
return false;
|
|
446
532
|
}
|
|
447
533
|
/**
|
|
448
|
-
* Compares two
|
|
449
|
-
*
|
|
450
|
-
* @param {Timestamp}
|
|
451
|
-
* @
|
|
534
|
+
* Compares two Timestamp objects for exact date, time, and timezone equality.
|
|
535
|
+
*
|
|
536
|
+
* @param {Timestamp} ts1 First Timestamp object.
|
|
537
|
+
* @param {Timestamp} ts2 Second Timestamp object.
|
|
538
|
+
* @returns {boolean} True when both timestamps match exactly.
|
|
452
539
|
*/
|
|
453
540
|
export function compareTimestamps(ts1, ts2) {
|
|
454
541
|
if (!ts1 || !ts2)
|
|
@@ -463,41 +550,44 @@ export function compareTimestamps(ts1, ts2) {
|
|
|
463
550
|
ts1.timezone === ts2.timezone);
|
|
464
551
|
}
|
|
465
552
|
/**
|
|
466
|
-
* Compares the date of two
|
|
467
|
-
*
|
|
468
|
-
* @param {Timestamp}
|
|
469
|
-
* @
|
|
553
|
+
* Compares the calendar date portion of two Timestamp objects.
|
|
554
|
+
*
|
|
555
|
+
* @param {Timestamp} ts1 First Timestamp object.
|
|
556
|
+
* @param {Timestamp} ts2 Second Timestamp object.
|
|
557
|
+
* @returns {boolean} True when both dates are the same.
|
|
470
558
|
*/
|
|
471
559
|
export function compareDate(ts1, ts2) {
|
|
472
560
|
return getDate(ts1) === getDate(ts2);
|
|
473
561
|
}
|
|
474
562
|
/**
|
|
475
|
-
* Compares the time of two
|
|
476
|
-
*
|
|
477
|
-
* @param {Timestamp}
|
|
478
|
-
* @
|
|
563
|
+
* Compares the formatted time portion of two Timestamp objects.
|
|
564
|
+
*
|
|
565
|
+
* @param {Timestamp} ts1 First Timestamp object.
|
|
566
|
+
* @param {Timestamp} ts2 Second Timestamp object.
|
|
567
|
+
* @returns {boolean} True when both times are the same.
|
|
479
568
|
*/
|
|
480
569
|
export function compareTime(ts1, ts2) {
|
|
481
570
|
return getTime(ts1) === getTime(ts2);
|
|
482
571
|
}
|
|
483
572
|
/**
|
|
484
|
-
* Compares the date and time of two
|
|
485
|
-
*
|
|
486
|
-
* @param {Timestamp}
|
|
487
|
-
* @
|
|
573
|
+
* Compares the formatted date and time portions of two Timestamp objects.
|
|
574
|
+
*
|
|
575
|
+
* @param {Timestamp} ts1 First Timestamp object.
|
|
576
|
+
* @param {Timestamp} ts2 Second Timestamp object.
|
|
577
|
+
* @returns {boolean} True when both date-time values are the same.
|
|
488
578
|
*/
|
|
489
579
|
export function compareDateTime(ts1, ts2) {
|
|
490
580
|
return getDateTime(ts1) === getDateTime(ts2);
|
|
491
581
|
}
|
|
492
582
|
/**
|
|
493
|
-
*
|
|
583
|
+
* Converts a supported date or date-time string into a formatted Timestamp object.
|
|
494
584
|
*
|
|
495
585
|
* If `now` is supplied, the returned timestamp also includes relative flags
|
|
496
586
|
* such as `past`, `current`, `future`, and `currentWeekday`.
|
|
497
587
|
*
|
|
498
|
-
* @param {string} input
|
|
499
|
-
* @param {Timestamp} now
|
|
500
|
-
* @returns {Timestamp}
|
|
588
|
+
* @param {string} input Date or date-time string, such as `YYYY-MM-DD`, `YYYY-MM-DD HH:mm:ss`, or an ISO-like value with optional milliseconds and timezone suffix.
|
|
589
|
+
* @param {Timestamp} now Optional Timestamp used to calculate relative flags.
|
|
590
|
+
* @returns {Timestamp} Formatted Timestamp object, or `null` when the input cannot be parsed.
|
|
501
591
|
*/
|
|
502
592
|
export function parseTimestamp(input, now = null) {
|
|
503
593
|
let timestamp = parsed(input);
|
|
@@ -510,9 +600,10 @@ export function parseTimestamp(input, now = null) {
|
|
|
510
600
|
return timestamp;
|
|
511
601
|
}
|
|
512
602
|
/**
|
|
513
|
-
* Converts a
|
|
514
|
-
*
|
|
515
|
-
* @
|
|
603
|
+
* Converts a Timestamp date into a sortable numeric identifier.
|
|
604
|
+
*
|
|
605
|
+
* @param {Timestamp} timestamp Timestamp object to read.
|
|
606
|
+
* @returns {number} Numeric date identifier.
|
|
516
607
|
*/
|
|
517
608
|
export function getDayIdentifier(timestamp) {
|
|
518
609
|
return ((timestamp.year ?? 0) * 100000000 +
|
|
@@ -520,9 +611,10 @@ export function getDayIdentifier(timestamp) {
|
|
|
520
611
|
(timestamp.day ?? 0) * 10000);
|
|
521
612
|
}
|
|
522
613
|
/**
|
|
523
|
-
* Converts a
|
|
524
|
-
*
|
|
525
|
-
* @
|
|
614
|
+
* Converts a Timestamp time into a sortable numeric identifier.
|
|
615
|
+
*
|
|
616
|
+
* @param {Timestamp} timestamp Timestamp object to read.
|
|
617
|
+
* @returns {number} Numeric time identifier.
|
|
526
618
|
*/
|
|
527
619
|
export function getTimeIdentifier(timestamp) {
|
|
528
620
|
return (timestamp.hour ?? 0) * 100 + (timestamp.minute ?? 0);
|
|
@@ -535,17 +627,18 @@ function getTimeComparisonValue(timestamp) {
|
|
|
535
627
|
(timestamp.millisecond ?? 0));
|
|
536
628
|
}
|
|
537
629
|
/**
|
|
538
|
-
* Converts a
|
|
539
|
-
*
|
|
540
|
-
* @
|
|
630
|
+
* Converts a Timestamp date and time into a sortable numeric identifier.
|
|
631
|
+
*
|
|
632
|
+
* @param {Timestamp} timestamp Timestamp object to read.
|
|
633
|
+
* @returns {number} Numeric date-time identifier.
|
|
541
634
|
*/
|
|
542
635
|
export function getDayTimeIdentifier(timestamp) {
|
|
543
636
|
return getDayIdentifier(timestamp) + getTimeIdentifier(timestamp);
|
|
544
637
|
}
|
|
545
638
|
/**
|
|
546
|
-
* Returns the difference between two
|
|
547
|
-
* @param {Timestamp} ts1 The first
|
|
548
|
-
* @param {Timestamp} ts2 The second
|
|
639
|
+
* Returns the difference between two Timestamps
|
|
640
|
+
* @param {Timestamp} ts1 The first Timestamp
|
|
641
|
+
* @param {Timestamp} ts2 The second Timestamp
|
|
549
642
|
* @param {boolean=} strict Optional flag to not to return negative numbers
|
|
550
643
|
* @returns {number} The difference
|
|
551
644
|
*/
|
|
@@ -560,11 +653,16 @@ export function diffTimestamp(ts1, ts2, strict = false) {
|
|
|
560
653
|
return utc2 - utc1;
|
|
561
654
|
}
|
|
562
655
|
/**
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
*
|
|
656
|
+
* Returns a Timestamp with relative flags compared to a supplied `now` value.
|
|
657
|
+
*
|
|
658
|
+
* The returned object includes `past`, `current`, `future`, and
|
|
659
|
+
* `currentWeekday` flags. Pass `true` for `time` when both values should be
|
|
660
|
+
* compared at time-of-day precision.
|
|
661
|
+
*
|
|
662
|
+
* @param {Timestamp} timestamp Timestamp object to update.
|
|
663
|
+
* @param {Timestamp} now Timestamp representing the comparison point.
|
|
664
|
+
* @param {boolean=} time Include time-of-day in the comparison when true.
|
|
665
|
+
* @returns {Timestamp} New Timestamp object with relative flags.
|
|
568
666
|
*/
|
|
569
667
|
export function updateRelative(timestamp, now, time = false) {
|
|
570
668
|
const ts = cloneTimestamp(timestamp);
|
|
@@ -588,10 +686,10 @@ export function updateRelative(timestamp, now, time = false) {
|
|
|
588
686
|
* The returned timestamp has updated hour/minute fields and clears second and
|
|
589
687
|
* millisecond precision because this helper is minute-oriented.
|
|
590
688
|
*
|
|
591
|
-
* @param {Timestamp} timestamp The
|
|
689
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
592
690
|
* @param {number} minutes The number of minutes to set from midnight
|
|
593
|
-
* @param {Timestamp=} now Optional
|
|
594
|
-
* @returns {Timestamp} A new
|
|
691
|
+
* @param {Timestamp=} now Optional Timestamp representing current date and time
|
|
692
|
+
* @returns {Timestamp} A new Timestamp
|
|
595
693
|
*/
|
|
596
694
|
export function updateMinutes(timestamp, minutes, now = null) {
|
|
597
695
|
let ts = cloneTimestamp(timestamp);
|
|
@@ -607,8 +705,8 @@ export function updateMinutes(timestamp, minutes, now = null) {
|
|
|
607
705
|
return freezeTimestamp(ts);
|
|
608
706
|
}
|
|
609
707
|
/**
|
|
610
|
-
* Updates the
|
|
611
|
-
* @param {Timestamp} timestamp The
|
|
708
|
+
* Updates the Timestamp with the weekday
|
|
709
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
612
710
|
* @returns A new Timestamp
|
|
613
711
|
*/
|
|
614
712
|
export function updateWeekday(timestamp) {
|
|
@@ -617,8 +715,8 @@ export function updateWeekday(timestamp) {
|
|
|
617
715
|
return freezeTimestamp(ts);
|
|
618
716
|
}
|
|
619
717
|
/**
|
|
620
|
-
* Updates the
|
|
621
|
-
* @param {Timestamp} timestamp The
|
|
718
|
+
* Updates the Timestamp with the day of the year (doy)
|
|
719
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
622
720
|
* @returns A new Timestamp
|
|
623
721
|
*/
|
|
624
722
|
export function updateDayOfYear(timestamp) {
|
|
@@ -627,9 +725,9 @@ export function updateDayOfYear(timestamp) {
|
|
|
627
725
|
return freezeTimestamp(ts);
|
|
628
726
|
}
|
|
629
727
|
/**
|
|
630
|
-
* Updates the
|
|
631
|
-
* @param {Timestamp} timestamp The
|
|
632
|
-
* @returns A new
|
|
728
|
+
* Updates the Timestamp with the workweek
|
|
729
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
730
|
+
* @returns A new Timestamp
|
|
633
731
|
*/
|
|
634
732
|
export function updateWorkWeek(timestamp) {
|
|
635
733
|
const ts = cloneTimestamp(timestamp);
|
|
@@ -682,13 +780,13 @@ function isTimestampInDisabledDay(timestamp, day) {
|
|
|
682
780
|
return disabledDay !== null && getDayIdentifier(disabledDay) === target;
|
|
683
781
|
}
|
|
684
782
|
/**
|
|
685
|
-
* Updates the passed
|
|
686
|
-
* @param {Timestamp} timestamp The
|
|
783
|
+
* Updates the passed Timestamp with disabled, if needed
|
|
784
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
687
785
|
* @param {string} [disabledBefore] In `YYYY-MM-DD` format
|
|
688
786
|
* @param {string} [disabledAfter] In `YYYY-MM-DD` format
|
|
689
787
|
* @param {number[]} [disabledWeekdays] An array of numbers representing weekdays [0 = Sun, ..., 6 = Sat]
|
|
690
788
|
* @param {DisabledDays} [disabledDays] An array of days in 'YYYY-MM-DD' format. If an array with a pair of dates is in first array, then this is treated as a range. Object entries can include date/from/to plus color metadata.
|
|
691
|
-
* @returns A new
|
|
789
|
+
* @returns A new Timestamp
|
|
692
790
|
*/
|
|
693
791
|
export function updateDisabled(timestamp, disabledBefore, disabledAfter, disabledWeekdays, disabledDays) {
|
|
694
792
|
let ts = cloneTimestamp(timestamp);
|
|
@@ -730,9 +828,9 @@ export function updateDisabled(timestamp, disabledBefore, disabledAfter, disable
|
|
|
730
828
|
return freezeTimestamp(ts);
|
|
731
829
|
}
|
|
732
830
|
/**
|
|
733
|
-
* Updates the passed
|
|
734
|
-
* @param {Timestamp} timestamp The
|
|
735
|
-
* @returns A new
|
|
831
|
+
* Updates the passed Timestamp with formatted data (time string, date string, weekday, day of year and workweek)
|
|
832
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
833
|
+
* @returns A new Timestamp
|
|
736
834
|
*/
|
|
737
835
|
export function updateFormatted(timestamp) {
|
|
738
836
|
const ts = cloneTimestamp(timestamp);
|
|
@@ -745,8 +843,8 @@ export function updateFormatted(timestamp) {
|
|
|
745
843
|
return freezeTimestamp(ts);
|
|
746
844
|
}
|
|
747
845
|
/**
|
|
748
|
-
* Returns day of the year (doy) for the passed in
|
|
749
|
-
* @param {Timestamp} timestamp The
|
|
846
|
+
* Returns day of the year (doy) for the passed in Timestamp
|
|
847
|
+
* @param {Timestamp} timestamp The Timestamp to use
|
|
750
848
|
* @returns {number} The day of the year
|
|
751
849
|
*/
|
|
752
850
|
export function getDayOfYear(timestamp) {
|
|
@@ -760,8 +858,8 @@ export function getDayOfYear(timestamp) {
|
|
|
760
858
|
1000);
|
|
761
859
|
}
|
|
762
860
|
/**
|
|
763
|
-
* Returns workweek for the passed in
|
|
764
|
-
* @param {Timestamp} timestamp The
|
|
861
|
+
* Returns workweek for the passed in Timestamp
|
|
862
|
+
* @param {Timestamp} timestamp The Timestamp to use
|
|
765
863
|
* @returns {number} The work week
|
|
766
864
|
*/
|
|
767
865
|
export function getWorkWeek(timestamp) {
|
|
@@ -787,8 +885,8 @@ export function getWorkWeek(timestamp) {
|
|
|
787
885
|
return weekNumber;
|
|
788
886
|
}
|
|
789
887
|
/**
|
|
790
|
-
* Returns weekday for the passed in
|
|
791
|
-
* @param {Timestamp} timestamp The
|
|
888
|
+
* Returns weekday for the passed in Timestamp
|
|
889
|
+
* @param {Timestamp} timestamp The Timestamp to use
|
|
792
890
|
* @returns {number} The weekday
|
|
793
891
|
*/
|
|
794
892
|
export function getWeekday(timestamp) {
|
|
@@ -813,17 +911,80 @@ export function getWeekday(timestamp) {
|
|
|
813
911
|
return weekday ?? 0;
|
|
814
912
|
}
|
|
815
913
|
/**
|
|
816
|
-
*
|
|
817
|
-
*
|
|
818
|
-
* @
|
|
914
|
+
* Returns an immutable copy of a Timestamp object.
|
|
915
|
+
*
|
|
916
|
+
* @param {Timestamp} timestamp Timestamp object to copy.
|
|
917
|
+
* @returns {Timestamp} Frozen Timestamp copy.
|
|
819
918
|
*/
|
|
820
919
|
export function copyTimestamp(timestamp) {
|
|
821
920
|
return freezeTimestamp(timestamp);
|
|
822
921
|
}
|
|
922
|
+
function setTimeParts(timestamp, hour, minute, second, millisecond) {
|
|
923
|
+
const ts = cloneTimestamp(timestamp);
|
|
924
|
+
ts.hasTime = true;
|
|
925
|
+
ts.hour = hour;
|
|
926
|
+
ts.minute = minute;
|
|
927
|
+
if (second === undefined) {
|
|
928
|
+
delete ts.second;
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
ts.second = second;
|
|
932
|
+
}
|
|
933
|
+
if (millisecond === undefined) {
|
|
934
|
+
delete ts.millisecond;
|
|
935
|
+
}
|
|
936
|
+
else {
|
|
937
|
+
ts.millisecond = millisecond;
|
|
938
|
+
}
|
|
939
|
+
return updateFormatted(ts);
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Returns a Timestamp at the start of the same calendar day.
|
|
943
|
+
*
|
|
944
|
+
* @param {Timestamp} timestamp Timestamp object to transform.
|
|
945
|
+
* @returns {Timestamp} New Timestamp at `00:00`.
|
|
946
|
+
*/
|
|
947
|
+
export function getStartOfDay(timestamp) {
|
|
948
|
+
return setTimeParts(timestamp, 0, 0);
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Returns a Timestamp at the end of the same calendar day.
|
|
952
|
+
*
|
|
953
|
+
* @param {Timestamp} timestamp Timestamp object to transform.
|
|
954
|
+
* @returns {Timestamp} New Timestamp at `23:59:59.999`.
|
|
955
|
+
*/
|
|
956
|
+
export function getEndOfDay(timestamp) {
|
|
957
|
+
return setTimeParts(timestamp, 23, 59, 59, 999);
|
|
958
|
+
}
|
|
959
|
+
/**
|
|
960
|
+
* Returns a Timestamp at the start of the same Gregorian year.
|
|
961
|
+
*
|
|
962
|
+
* @param {Timestamp} timestamp Timestamp object to transform.
|
|
963
|
+
* @returns {Timestamp} New Timestamp for January 1 at `00:00`.
|
|
964
|
+
*/
|
|
965
|
+
export function getStartOfYear(timestamp) {
|
|
966
|
+
const ts = cloneTimestamp(timestamp);
|
|
967
|
+
ts.month = MONTH_MIN;
|
|
968
|
+
ts.day = DAY_MIN;
|
|
969
|
+
return getStartOfDay(updateFormatted(ts));
|
|
970
|
+
}
|
|
971
|
+
/**
|
|
972
|
+
* Returns a Timestamp at the end of the same Gregorian year.
|
|
973
|
+
*
|
|
974
|
+
* @param {Timestamp} timestamp Timestamp object to transform.
|
|
975
|
+
* @returns {Timestamp} New Timestamp for December 31 at `23:59:59.999`.
|
|
976
|
+
*/
|
|
977
|
+
export function getEndOfYear(timestamp) {
|
|
978
|
+
const ts = cloneTimestamp(timestamp);
|
|
979
|
+
ts.month = MONTH_MAX;
|
|
980
|
+
ts.day = daysInMonth(ts.year, MONTH_MAX);
|
|
981
|
+
return getEndOfDay(updateFormatted(ts));
|
|
982
|
+
}
|
|
823
983
|
/**
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
* @
|
|
984
|
+
* Formats the date portion of a Timestamp object.
|
|
985
|
+
*
|
|
986
|
+
* @param {Timestamp} timestamp Timestamp object to format.
|
|
987
|
+
* @returns {string} Date string such as `YYYY-MM-DD`.
|
|
827
988
|
*/
|
|
828
989
|
export function getDate(timestamp) {
|
|
829
990
|
let str = `${padNumber(timestamp.year, 4)}-${padNumber(timestamp.month, 2)}`;
|
|
@@ -832,9 +993,13 @@ export function getDate(timestamp) {
|
|
|
832
993
|
return str;
|
|
833
994
|
}
|
|
834
995
|
/**
|
|
835
|
-
*
|
|
836
|
-
*
|
|
837
|
-
*
|
|
996
|
+
* Formats the time portion of a Timestamp object.
|
|
997
|
+
*
|
|
998
|
+
* Minute precision is formatted as `HH:mm`; second precision as `HH:mm:ss`;
|
|
999
|
+
* millisecond precision as `HH:mm:ss.SSS`.
|
|
1000
|
+
*
|
|
1001
|
+
* @param {Timestamp} timestamp Timestamp object to format.
|
|
1002
|
+
* @returns {string} Time string, or an empty string when the timestamp has no time.
|
|
838
1003
|
*/
|
|
839
1004
|
export function getTime(timestamp) {
|
|
840
1005
|
if (!timestamp.hasTime) {
|
|
@@ -850,31 +1015,32 @@ export function getTime(timestamp) {
|
|
|
850
1015
|
return time;
|
|
851
1016
|
}
|
|
852
1017
|
/**
|
|
853
|
-
*
|
|
854
|
-
*
|
|
855
|
-
* @
|
|
1018
|
+
* Formats a Timestamp as date plus time.
|
|
1019
|
+
*
|
|
1020
|
+
* @param {Timestamp} timestamp Timestamp object to format.
|
|
1021
|
+
* @returns {string} Date-time string such as `YYYY-MM-DD HH:mm`.
|
|
856
1022
|
*/
|
|
857
1023
|
export function getDateTime(timestamp) {
|
|
858
1024
|
return getDate(timestamp) + " " + (timestamp.hasTime ? getTime(timestamp) : "00:00");
|
|
859
1025
|
}
|
|
860
1026
|
/**
|
|
861
|
-
*
|
|
862
|
-
* @param {Timestamp} timestamp The
|
|
1027
|
+
* Alias for relativeDays.
|
|
1028
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
863
1029
|
* @param {function} [mover=nextDay] The mover function to use (ie: {nextDay} or {prevDay}).
|
|
864
1030
|
* @param {number} [days=1] The number of days to move.
|
|
865
1031
|
* @param {number[]} [allowedWeekdays=[ 0, 1, 2, 3, 4, 5, 6 ]] An array of numbers representing the weekdays. ie: [0 = Sun, ..., 6 = Sat].
|
|
866
|
-
* @returns A new
|
|
1032
|
+
* @returns A new Timestamp
|
|
867
1033
|
*/
|
|
868
1034
|
export function moveRelativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6]) {
|
|
869
1035
|
return relativeDays(timestamp, mover, days, allowedWeekdays);
|
|
870
1036
|
}
|
|
871
1037
|
/**
|
|
872
|
-
* Moves the
|
|
873
|
-
* @param {Timestamp} timestamp The
|
|
1038
|
+
* Moves the Timestamp the number of relative days
|
|
1039
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
874
1040
|
* @param {function} [mover=nextDay] The mover function to use (ie: {nextDay} or {prevDay}).
|
|
875
1041
|
* @param {number} [days=1] The number of days to move.
|
|
876
1042
|
* @param {number[]} [allowedWeekdays=[ 0, 1, 2, 3, 4, 5, 6 ]] An array of numbers representing the weekdays. ie: [0 = Sun, ..., 6 = Sat].
|
|
877
|
-
* @returns A new
|
|
1043
|
+
* @returns A new Timestamp
|
|
878
1044
|
*/
|
|
879
1045
|
export function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekdays = [0, 1, 2, 3, 4, 5, 6]) {
|
|
880
1046
|
let ts = copyTimestamp(timestamp);
|
|
@@ -890,12 +1056,12 @@ export function relativeDays(timestamp, mover = nextDay, days = 1, allowedWeekda
|
|
|
890
1056
|
return ts;
|
|
891
1057
|
}
|
|
892
1058
|
/**
|
|
893
|
-
* Finds the specified weekday (forward or back) based on the
|
|
894
|
-
* @param {Timestamp} timestamp The
|
|
1059
|
+
* Finds the specified weekday (forward or back) based on the Timestamp
|
|
1060
|
+
* @param {Timestamp} timestamp The Timestamp to transform
|
|
895
1061
|
* @param {number} weekday The weekday number (Sun = 0, ..., Sat = 6)
|
|
896
1062
|
* @param {function} [mover=nextDay] The function to use ({prevDay} or {nextDay}).
|
|
897
1063
|
* @param {number} [maxDays=6] The number of days to look forward or back.
|
|
898
|
-
* @returns A new
|
|
1064
|
+
* @returns A new Timestamp
|
|
899
1065
|
*/
|
|
900
1066
|
export function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
|
|
901
1067
|
let ts = copyTimestamp(timestamp);
|
|
@@ -904,18 +1070,22 @@ export function findWeekday(timestamp, weekday, mover = nextDay, maxDays = 6) {
|
|
|
904
1070
|
return ts;
|
|
905
1071
|
}
|
|
906
1072
|
/**
|
|
907
|
-
* Creates an
|
|
908
|
-
*
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
*
|
|
912
|
-
* @param {
|
|
913
|
-
* @param {
|
|
914
|
-
* @param {
|
|
915
|
-
* @param {
|
|
916
|
-
* @param {
|
|
917
|
-
* @param {
|
|
918
|
-
* @
|
|
1073
|
+
* Creates an inclusive list of Timestamp days between start and end.
|
|
1074
|
+
*
|
|
1075
|
+
* The returned days are formatted, marked with relative flags against `now`,
|
|
1076
|
+
* and can include disabled metadata when disabled options are supplied.
|
|
1077
|
+
*
|
|
1078
|
+
* @param {Timestamp} start First day in the list.
|
|
1079
|
+
* @param {Timestamp} end Last day boundary for the list.
|
|
1080
|
+
* @param {Timestamp} now Timestamp used to calculate relative flags.
|
|
1081
|
+
* @param {number[]} weekdays Weekday numbers to include, from `0` Sunday to `6` Saturday.
|
|
1082
|
+
* @param {string} [disabledBefore] Disable days before this `YYYY-MM-DD` date.
|
|
1083
|
+
* @param {string} [disabledAfter] Disable days after this `YYYY-MM-DD` date.
|
|
1084
|
+
* @param {number[]} [disabledWeekdays] Weekday numbers to mark disabled.
|
|
1085
|
+
* @param {DisabledDays} [disabledDays] Specific dates or date ranges to mark disabled.
|
|
1086
|
+
* @param {number} [max=42] Maximum number of days to return.
|
|
1087
|
+
* @param {number} [min=0] Minimum number of days to return.
|
|
1088
|
+
* @returns {Timestamp[]} Timestamp days.
|
|
919
1089
|
*/
|
|
920
1090
|
export function createDayList(start, end, now, weekdays = [0, 1, 2, 3, 4, 5, 6], disabledBefore = undefined, disabledAfter = undefined, disabledWeekdays = [], disabledDays = [], max = 42, min = 0) {
|
|
921
1091
|
const begin = getDayIdentifier(start);
|
|
@@ -947,13 +1117,14 @@ export function createDayList(start, end, now, weekdays = [0, 1, 2, 3, 4, 5, 6],
|
|
|
947
1117
|
return days;
|
|
948
1118
|
}
|
|
949
1119
|
/**
|
|
950
|
-
* Creates an array of interval
|
|
951
|
-
*
|
|
952
|
-
* @param {
|
|
953
|
-
* @param {number}
|
|
954
|
-
* @param {number}
|
|
955
|
-
* @param {
|
|
956
|
-
* @
|
|
1120
|
+
* Creates an array of interval Timestamp objects for one day.
|
|
1121
|
+
*
|
|
1122
|
+
* @param {Timestamp} timestamp Base date for the intervals.
|
|
1123
|
+
* @param {number} first Starting interval index.
|
|
1124
|
+
* @param {number} minutes Minutes between intervals, such as 60, 30, or 15.
|
|
1125
|
+
* @param {number} count Number of intervals to create.
|
|
1126
|
+
* @param {Timestamp} now Timestamp used to calculate relative flags.
|
|
1127
|
+
* @returns {Timestamp[]} Interval Timestamp objects.
|
|
957
1128
|
*/
|
|
958
1129
|
export function createIntervalList(timestamp, first, minutes, count, now) {
|
|
959
1130
|
const intervals = [];
|
|
@@ -965,76 +1136,150 @@ export function createIntervalList(timestamp, first, minutes, count, now) {
|
|
|
965
1136
|
}
|
|
966
1137
|
/**
|
|
967
1138
|
* @callback getOptions
|
|
968
|
-
* @param {Timestamp} timestamp A
|
|
1139
|
+
* @param {Timestamp} timestamp A Timestamp object
|
|
969
1140
|
* @param {boolean} short True if using short options
|
|
970
1141
|
* @returns {Object} An Intl object representing options to be used
|
|
971
1142
|
*/
|
|
972
1143
|
/**
|
|
973
1144
|
* @callback formatter
|
|
974
|
-
* @param {Timestamp} timestamp The
|
|
1145
|
+
* @param {Timestamp} timestamp The Timestamp being used
|
|
975
1146
|
* @param {boolean} short If short format is being requested
|
|
976
|
-
* @returns {string} The localized string of the formatted
|
|
1147
|
+
* @returns {string} The localized string of the formatted Timestamp
|
|
977
1148
|
*/
|
|
978
|
-
|
|
979
|
-
* Returns a locale formatter backed by `Intl.DateTimeFormat`.
|
|
980
|
-
*
|
|
981
|
-
* The helper is SSR-safe: if `Intl.DateTimeFormat` is unavailable in a target
|
|
982
|
-
* runtime, it returns a formatter that produces an empty string instead of
|
|
983
|
-
* throwing during module load.
|
|
984
|
-
*
|
|
985
|
-
* @param {string} locale The locale to use (ie: en-US)
|
|
986
|
-
* @param {getOptions} cb The function to call for options. This function should return an Intl formatted object. The function is passed (timestamp, short).
|
|
987
|
-
* @returns {formatter} The function has params (timestamp, short). The short is to use the short options.
|
|
988
|
-
*/
|
|
989
|
-
export function createNativeLocaleFormatter(locale, cb) {
|
|
1149
|
+
function createNativeLocaleFormatterByMode(locale, cb, toDate) {
|
|
990
1150
|
const emptyFormatter = () => "";
|
|
991
|
-
/* istanbul ignore next */
|
|
992
1151
|
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") {
|
|
993
1152
|
return emptyFormatter;
|
|
994
1153
|
}
|
|
995
1154
|
return (timestamp, short) => {
|
|
996
1155
|
try {
|
|
997
1156
|
const intlFormatter = new Intl.DateTimeFormat(locale || undefined, cb(timestamp, short));
|
|
998
|
-
return intlFormatter.format(
|
|
1157
|
+
return intlFormatter.format(toDate(timestamp));
|
|
999
1158
|
}
|
|
1000
|
-
catch (e)
|
|
1159
|
+
catch (e) {
|
|
1001
1160
|
console.error(`Intl.DateTimeFormat: ${e.message} -> ${getDateTime(timestamp)}`);
|
|
1002
1161
|
return "";
|
|
1003
1162
|
}
|
|
1004
1163
|
};
|
|
1005
1164
|
}
|
|
1006
1165
|
/**
|
|
1007
|
-
*
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
1010
|
-
*
|
|
1166
|
+
* Returns a host-local locale formatter backed by `Intl.DateTimeFormat`.
|
|
1167
|
+
*
|
|
1168
|
+
* The helper is SSR-safe: if `Intl.DateTimeFormat` is unavailable in a target
|
|
1169
|
+
* runtime, it returns a formatter that produces an empty string instead of
|
|
1170
|
+
* throwing during module load.
|
|
1171
|
+
*
|
|
1172
|
+
* Use `createNativeLocaleFormatterUTC()` when Timestamp values should be read
|
|
1173
|
+
* as UTC fields before formatting.
|
|
1174
|
+
*
|
|
1175
|
+
* @param {string} locale The locale to use (ie: en-US)
|
|
1176
|
+
* @param {getOptions} cb The function to call for options. This function should return an Intl formatted object. The function is passed (timestamp, short).
|
|
1177
|
+
* @returns {formatter} The function has params (timestamp, short). The short is to use the short options.
|
|
1178
|
+
*/
|
|
1179
|
+
export function createNativeLocaleFormatter(locale, cb) {
|
|
1180
|
+
return createNativeLocaleFormatterByMode(locale, cb, makeDateTime);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Returns a UTC locale formatter backed by `Intl.DateTimeFormat`.
|
|
1184
|
+
*
|
|
1185
|
+
* This helper constructs the native `Date` with UTC fields before formatting.
|
|
1186
|
+
* Pair it with `timeZone: "UTC"` when calendar labels must remain pinned to
|
|
1187
|
+
* the Timestamp's UTC date instead of the viewer's local timezone.
|
|
1188
|
+
*
|
|
1189
|
+
* @param {string} locale The locale to use (ie: en-US)
|
|
1190
|
+
* @param {getOptions} cb The function to call for options. This function should return an Intl formatted object. The function is passed (timestamp, short).
|
|
1191
|
+
* @returns {formatter} The function has params (timestamp, short). The short is to use the short options.
|
|
1192
|
+
*/
|
|
1193
|
+
export function createNativeLocaleFormatterUTC(locale, cb) {
|
|
1194
|
+
return createNativeLocaleFormatterByMode(locale, cb, makeDateTimeUTC);
|
|
1195
|
+
}
|
|
1196
|
+
/**
|
|
1197
|
+
* Converts a Timestamp date into a host-local JavaScript Date.
|
|
1198
|
+
*
|
|
1199
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1200
|
+
* @returns {Date} Host-local JavaScript Date object.
|
|
1011
1201
|
*/
|
|
1012
|
-
export function makeDate(timestamp
|
|
1013
|
-
if (utc)
|
|
1014
|
-
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, 0, 0));
|
|
1202
|
+
export function makeDate(timestamp) {
|
|
1015
1203
|
return new Date(timestamp.year, timestamp.month - 1, timestamp.day, 0, 0);
|
|
1016
1204
|
}
|
|
1017
1205
|
/**
|
|
1018
|
-
*
|
|
1019
|
-
*
|
|
1020
|
-
* @param {
|
|
1021
|
-
* @returns {Date}
|
|
1206
|
+
* Converts a Timestamp date into a UTC JavaScript Date.
|
|
1207
|
+
*
|
|
1208
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1209
|
+
* @returns {Date} JavaScript Date object built with `Date.UTC()`.
|
|
1210
|
+
*/
|
|
1211
|
+
export function makeDateUTC(timestamp) {
|
|
1212
|
+
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, 0, 0));
|
|
1213
|
+
}
|
|
1214
|
+
/**
|
|
1215
|
+
* Converts a Timestamp date and time into a host-local JavaScript Date.
|
|
1216
|
+
*
|
|
1217
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1218
|
+
* @returns {Date} Host-local JavaScript Date object.
|
|
1022
1219
|
*/
|
|
1023
|
-
export function makeDateTime(timestamp
|
|
1024
|
-
if (utc)
|
|
1025
|
-
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0));
|
|
1220
|
+
export function makeDateTime(timestamp) {
|
|
1026
1221
|
return new Date(timestamp.year, timestamp.month - 1, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0);
|
|
1027
1222
|
}
|
|
1028
1223
|
/**
|
|
1029
|
-
* Converts a
|
|
1224
|
+
* Converts a Timestamp date and time into a UTC JavaScript Date.
|
|
1225
|
+
*
|
|
1226
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1227
|
+
* @returns {Date} JavaScript Date object built with `Date.UTC()`.
|
|
1228
|
+
*/
|
|
1229
|
+
export function makeDateTimeUTC(timestamp) {
|
|
1230
|
+
return new Date(Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day, timestamp.hour, timestamp.minute, timestamp.second ?? 0, timestamp.millisecond ?? 0));
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Converts a Timestamp into Unix milliseconds by reading its fields as UTC.
|
|
1234
|
+
*
|
|
1235
|
+
* This is deterministic across server and client runtimes. It does not read or
|
|
1236
|
+
* convert the optional `timezone` suffix stored on the Timestamp.
|
|
1237
|
+
*
|
|
1238
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1239
|
+
* @returns {number} Unix milliseconds.
|
|
1240
|
+
*/
|
|
1241
|
+
export function toUnixMilliseconds(timestamp) {
|
|
1242
|
+
return makeDateTimeUTC(timestamp).getTime();
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Converts a Timestamp into Unix seconds by reading its fields as UTC.
|
|
1246
|
+
*
|
|
1247
|
+
* Milliseconds are floored because Unix seconds are integer-oriented.
|
|
1248
|
+
*
|
|
1249
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1250
|
+
* @returns {number} Unix seconds.
|
|
1251
|
+
*/
|
|
1252
|
+
export function toUnixSeconds(timestamp) {
|
|
1253
|
+
return Math.floor(toUnixMilliseconds(timestamp) / MILLISECONDS_IN_SECOND);
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Converts Unix milliseconds into an immutable Timestamp using UTC fields.
|
|
1257
|
+
*
|
|
1258
|
+
* @param {number} milliseconds Unix milliseconds.
|
|
1259
|
+
* @returns {Timestamp | null} Timestamp built from UTC fields, or `null` for invalid input.
|
|
1260
|
+
*/
|
|
1261
|
+
export function fromUnixMilliseconds(milliseconds) {
|
|
1262
|
+
return parseDateUTC(new Date(milliseconds));
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Converts Unix seconds into an immutable Timestamp using UTC fields.
|
|
1266
|
+
*
|
|
1267
|
+
* @param {number} seconds Unix seconds.
|
|
1268
|
+
* @returns {Timestamp | null} Timestamp built from UTC fields, or `null` for invalid input.
|
|
1269
|
+
*/
|
|
1270
|
+
export function fromUnixSeconds(seconds) {
|
|
1271
|
+
return fromUnixMilliseconds(seconds * MILLISECONDS_IN_SECOND);
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Converts a Timestamp to a local JavaScript Date.
|
|
1030
1275
|
*
|
|
1031
|
-
* This is equivalent to `makeDateTime(timestamp
|
|
1276
|
+
* This is equivalent to `makeDateTime(timestamp)`.
|
|
1032
1277
|
*
|
|
1033
|
-
* @param {Timestamp} timestamp
|
|
1034
|
-
* @returns {Date}
|
|
1278
|
+
* @param {Timestamp} timestamp Timestamp object to convert.
|
|
1279
|
+
* @returns {Date} Local JavaScript Date object.
|
|
1035
1280
|
*/
|
|
1036
1281
|
export function getDateObject(timestamp) {
|
|
1037
|
-
return makeDateTime(timestamp
|
|
1282
|
+
return makeDateTime(timestamp);
|
|
1038
1283
|
}
|
|
1039
1284
|
/**
|
|
1040
1285
|
* Validates if the input is a finite number.
|
|
@@ -1047,10 +1292,11 @@ export function validateNumber(input) {
|
|
|
1047
1292
|
return isFinite(Number(input));
|
|
1048
1293
|
}
|
|
1049
1294
|
/**
|
|
1050
|
-
*
|
|
1051
|
-
*
|
|
1052
|
-
* @param {
|
|
1053
|
-
* @
|
|
1295
|
+
* Finds the latest Timestamp in an array.
|
|
1296
|
+
*
|
|
1297
|
+
* @param {Timestamp[]} timestamps Timestamp objects to compare.
|
|
1298
|
+
* @param {boolean=} useTime Include time-of-day in the comparison when true.
|
|
1299
|
+
* @returns Latest Timestamp object.
|
|
1054
1300
|
*/
|
|
1055
1301
|
export function maxTimestamp(timestamps, useTime = false) {
|
|
1056
1302
|
const func = useTime === true ? getDayTimeIdentifier : getDayIdentifier;
|
|
@@ -1059,10 +1305,11 @@ export function maxTimestamp(timestamps, useTime = false) {
|
|
|
1059
1305
|
});
|
|
1060
1306
|
}
|
|
1061
1307
|
/**
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
* @param {
|
|
1065
|
-
* @
|
|
1308
|
+
* Finds the earliest Timestamp in an array.
|
|
1309
|
+
*
|
|
1310
|
+
* @param {Timestamp[]} timestamps Timestamp objects to compare.
|
|
1311
|
+
* @param {boolean=} useTime Include time-of-day in the comparison when true.
|
|
1312
|
+
* @returns Earliest Timestamp object.
|
|
1066
1313
|
*/
|
|
1067
1314
|
export function minTimestamp(timestamps, useTime = false) {
|
|
1068
1315
|
const func = useTime === true ? getDayTimeIdentifier : getDayIdentifier;
|
|
@@ -1070,13 +1317,168 @@ export function minTimestamp(timestamps, useTime = false) {
|
|
|
1070
1317
|
return Math.min(func(prev), func(cur)) === func(prev) ? prev : cur;
|
|
1071
1318
|
});
|
|
1072
1319
|
}
|
|
1320
|
+
function getTimestampSortValue(timestamp, useTime) {
|
|
1321
|
+
if (useTime === true) {
|
|
1322
|
+
return toUnixMilliseconds(timestamp);
|
|
1323
|
+
}
|
|
1324
|
+
return Date.UTC(timestamp.year, timestamp.month - 1, timestamp.day);
|
|
1325
|
+
}
|
|
1326
|
+
function compareTimestampOrder(first, second, useTime) {
|
|
1327
|
+
return getTimestampSortValue(first, useTime) - getTimestampSortValue(second, useTime);
|
|
1328
|
+
}
|
|
1329
|
+
function createFrozenRange(start, end) {
|
|
1330
|
+
return Object.freeze({ start: copyTimestamp(start), end: copyTimestamp(end) });
|
|
1331
|
+
}
|
|
1332
|
+
function isRangeTouchingOrOverlapping(first, second, useTime) {
|
|
1333
|
+
const step = useTime ? 1 : MILLISECONDS_IN_DAY;
|
|
1334
|
+
return (getTimestampSortValue(second.start, useTime) <= getTimestampSortValue(first.end, useTime) + step);
|
|
1335
|
+
}
|
|
1336
|
+
function moveBoundary(timestamp, amount, useTime) {
|
|
1337
|
+
if (useTime === true) {
|
|
1338
|
+
return fromUnixMilliseconds(toUnixMilliseconds(timestamp) + amount);
|
|
1339
|
+
}
|
|
1340
|
+
return addToDate(timestamp, { day: amount });
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Creates an inclusive Timestamp range and normalizes start/end order.
|
|
1344
|
+
*
|
|
1345
|
+
* @param {Timestamp} start First boundary.
|
|
1346
|
+
* @param {Timestamp} end Second boundary.
|
|
1347
|
+
* @param {boolean=} useTime Include time-of-day when ordering boundaries.
|
|
1348
|
+
* @returns {TimestampRange} Frozen inclusive Timestamp range.
|
|
1349
|
+
*/
|
|
1350
|
+
export function createTimestampRange(start, end, useTime = false) {
|
|
1351
|
+
if (compareTimestampOrder(start, end, useTime) <= 0) {
|
|
1352
|
+
return createFrozenRange(start, end);
|
|
1353
|
+
}
|
|
1354
|
+
return createFrozenRange(end, start);
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* Checks whether a Timestamp falls inside an inclusive TimestampRange.
|
|
1358
|
+
*
|
|
1359
|
+
* @param {Timestamp} timestamp Timestamp object to test.
|
|
1360
|
+
* @param {TimestampRange} range Inclusive range to test against.
|
|
1361
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1362
|
+
* @returns {boolean} True when the timestamp is inside the range.
|
|
1363
|
+
*/
|
|
1364
|
+
export function isTimestampInRange(timestamp, range, useTime = false) {
|
|
1365
|
+
return isBetweenDates(timestamp, range.start, range.end, useTime);
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Checks whether two inclusive TimestampRange values overlap.
|
|
1369
|
+
*
|
|
1370
|
+
* @param {TimestampRange} first First range.
|
|
1371
|
+
* @param {TimestampRange} second Second range.
|
|
1372
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1373
|
+
* @returns {boolean} True when the ranges overlap.
|
|
1374
|
+
*/
|
|
1375
|
+
export function isRangeOverlapping(first, second, useTime = false) {
|
|
1376
|
+
const firstRange = createTimestampRange(first.start, first.end, useTime);
|
|
1377
|
+
const secondRange = createTimestampRange(second.start, second.end, useTime);
|
|
1378
|
+
return (getTimestampSortValue(firstRange.start, useTime) <=
|
|
1379
|
+
getTimestampSortValue(secondRange.end, useTime) &&
|
|
1380
|
+
getTimestampSortValue(secondRange.start, useTime) <=
|
|
1381
|
+
getTimestampSortValue(firstRange.end, useTime));
|
|
1382
|
+
}
|
|
1073
1383
|
/**
|
|
1074
|
-
*
|
|
1075
|
-
*
|
|
1076
|
-
* @param {
|
|
1077
|
-
* @param {
|
|
1078
|
-
* @param {boolean=} useTime
|
|
1079
|
-
* @returns {
|
|
1384
|
+
* Returns the inclusive intersection of two TimestampRange values.
|
|
1385
|
+
*
|
|
1386
|
+
* @param {TimestampRange} first First range.
|
|
1387
|
+
* @param {TimestampRange} second Second range.
|
|
1388
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1389
|
+
* @returns {TimestampRange | null} Intersected range, or `null` when the ranges do not overlap.
|
|
1390
|
+
*/
|
|
1391
|
+
export function intersectRanges(first, second, useTime = false) {
|
|
1392
|
+
if (isRangeOverlapping(first, second, useTime) === false) {
|
|
1393
|
+
return null;
|
|
1394
|
+
}
|
|
1395
|
+
const start = compareTimestampOrder(first.start, second.start, useTime) >= 0 ? first.start : second.start;
|
|
1396
|
+
const end = compareTimestampOrder(first.end, second.end, useTime) <= 0 ? first.end : second.end;
|
|
1397
|
+
return createTimestampRange(start, end, useTime);
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Merges overlapping or touching TimestampRange values.
|
|
1401
|
+
*
|
|
1402
|
+
* Date-only ranges touch when the next range starts on the next calendar day.
|
|
1403
|
+
* Time-aware ranges touch when the next range starts one millisecond after the
|
|
1404
|
+
* previous range ends.
|
|
1405
|
+
*
|
|
1406
|
+
* @param {TimestampRange[]} ranges Ranges to merge.
|
|
1407
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1408
|
+
* @returns {TimestampRange[]} Merged ranges sorted by start boundary.
|
|
1409
|
+
*/
|
|
1410
|
+
export function mergeRanges(ranges, useTime = false) {
|
|
1411
|
+
const sorted = ranges
|
|
1412
|
+
.map((range) => createTimestampRange(range.start, range.end, useTime))
|
|
1413
|
+
.sort((a, b) => compareTimestampOrder(a.start, b.start, useTime));
|
|
1414
|
+
const merged = [];
|
|
1415
|
+
for (const range of sorted) {
|
|
1416
|
+
const last = merged[merged.length - 1];
|
|
1417
|
+
if (last === undefined || isRangeTouchingOrOverlapping(last, range, useTime) === false) {
|
|
1418
|
+
merged.push(range);
|
|
1419
|
+
continue;
|
|
1420
|
+
}
|
|
1421
|
+
const end = compareTimestampOrder(last.end, range.end, useTime) >= 0 ? last.end : range.end;
|
|
1422
|
+
merged[merged.length - 1] = createFrozenRange(last.start, end);
|
|
1423
|
+
}
|
|
1424
|
+
return merged;
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* Subtracts blocked ranges from a source range.
|
|
1428
|
+
*
|
|
1429
|
+
* The result is useful for availability windows because it returns the pieces
|
|
1430
|
+
* of the source range that remain after each blocked range is removed.
|
|
1431
|
+
*
|
|
1432
|
+
* @param {TimestampRange} source Source range.
|
|
1433
|
+
* @param {TimestampRange[]} blocked Ranges to remove from the source.
|
|
1434
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1435
|
+
* @returns {TimestampRange[]} Remaining ranges.
|
|
1436
|
+
*/
|
|
1437
|
+
export function subtractRanges(source, blocked, useTime = false) {
|
|
1438
|
+
const normalizedSource = createTimestampRange(source.start, source.end, useTime);
|
|
1439
|
+
const blockers = mergeRanges(blocked, useTime);
|
|
1440
|
+
let available = [normalizedSource];
|
|
1441
|
+
for (const blocker of blockers) {
|
|
1442
|
+
const nextAvailable = [];
|
|
1443
|
+
for (const range of available) {
|
|
1444
|
+
const overlap = intersectRanges(range, blocker, useTime);
|
|
1445
|
+
if (overlap === null) {
|
|
1446
|
+
nextAvailable.push(range);
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
if (compareTimestampOrder(range.start, overlap.start, useTime) < 0) {
|
|
1450
|
+
nextAvailable.push(createTimestampRange(range.start, moveBoundary(overlap.start, -1, useTime), useTime));
|
|
1451
|
+
}
|
|
1452
|
+
if (compareTimestampOrder(overlap.end, range.end, useTime) < 0) {
|
|
1453
|
+
nextAvailable.push(createTimestampRange(moveBoundary(overlap.end, 1, useTime), range.end, useTime));
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
available = nextAvailable;
|
|
1457
|
+
}
|
|
1458
|
+
return available;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Finds open gaps inside a source range after occupied ranges are removed.
|
|
1462
|
+
*
|
|
1463
|
+
* This is an alias for subtractRanges() with naming that reads naturally in
|
|
1464
|
+
* booking, resource, and availability workflows.
|
|
1465
|
+
*
|
|
1466
|
+
* @param {TimestampRange} source Source range.
|
|
1467
|
+
* @param {TimestampRange[]} occupied Ranges that are not available.
|
|
1468
|
+
* @param {boolean=} useTime Include time-of-day in the comparison.
|
|
1469
|
+
* @returns {TimestampRange[]} Gap ranges.
|
|
1470
|
+
*/
|
|
1471
|
+
export function findRangeGaps(source, occupied, useTime = false) {
|
|
1472
|
+
return subtractRanges(source, occupied, useTime);
|
|
1473
|
+
}
|
|
1474
|
+
/**
|
|
1475
|
+
* Checks whether a Timestamp falls inside an inclusive range.
|
|
1476
|
+
*
|
|
1477
|
+
* @param {Timestamp} timestamp Timestamp object to test.
|
|
1478
|
+
* @param {Timestamp} startTimestamp Inclusive start boundary.
|
|
1479
|
+
* @param {Timestamp} endTimestamp Inclusive end boundary.
|
|
1480
|
+
* @param {boolean=} useTime Include time-of-day in the comparison when true.
|
|
1481
|
+
* @returns {boolean} True when the timestamp is inside the range.
|
|
1080
1482
|
*/
|
|
1081
1483
|
export function isBetweenDates(timestamp, startTimestamp, endTimestamp, useTime = false) {
|
|
1082
1484
|
const cd = getDayIdentifier(timestamp) + (useTime === true ? getTimeIdentifier(timestamp) : 0);
|
|
@@ -1085,12 +1487,13 @@ export function isBetweenDates(timestamp, startTimestamp, endTimestamp, useTime
|
|
|
1085
1487
|
return cd >= sd && cd <= ed;
|
|
1086
1488
|
}
|
|
1087
1489
|
/**
|
|
1088
|
-
*
|
|
1089
|
-
*
|
|
1090
|
-
* @param {Timestamp}
|
|
1091
|
-
* @param {Timestamp}
|
|
1092
|
-
* @param {Timestamp}
|
|
1093
|
-
* @
|
|
1490
|
+
* Checks whether two inclusive Timestamp ranges overlap.
|
|
1491
|
+
*
|
|
1492
|
+
* @param {Timestamp} startTimestamp Start of the first range.
|
|
1493
|
+
* @param {Timestamp} endTimestamp End of the first range.
|
|
1494
|
+
* @param {Timestamp} firstTimestamp Start of the second range.
|
|
1495
|
+
* @param {Timestamp} lastTimestamp End of the second range.
|
|
1496
|
+
* @returns {boolean} True when the ranges overlap.
|
|
1094
1497
|
*/
|
|
1095
1498
|
export function isOverlappingDates(startTimestamp, endTimestamp, firstTimestamp, lastTimestamp) {
|
|
1096
1499
|
const start = getDayIdentifier(startTimestamp);
|
|
@@ -1105,11 +1508,12 @@ export function isOverlappingDates(startTimestamp, endTimestamp, firstTimestamp,
|
|
|
1105
1508
|
/**
|
|
1106
1509
|
* Adds or subtracts date/time units from a timestamp.
|
|
1107
1510
|
*
|
|
1108
|
-
* This function returns a new frozen
|
|
1109
|
-
* timestamp passed in.
|
|
1511
|
+
* This function returns a new frozen Timestamp; it does not mutate the
|
|
1512
|
+
* timestamp passed in. Invalid target dates are normalized through JavaScript
|
|
1513
|
+
* Date rules, so month overflow can roll into the following month.
|
|
1110
1514
|
*
|
|
1111
|
-
* @param {Timestamp} timestamp
|
|
1112
|
-
* @param {Object} options
|
|
1515
|
+
* @param {Timestamp} timestamp Timestamp object to offset.
|
|
1516
|
+
* @param {Object} options Date/time units to add or subtract.
|
|
1113
1517
|
* @param {number=} options.year If positive, adds years. If negative, removes years.
|
|
1114
1518
|
* @param {number=} options.month If positive, adds months. If negative, removes month.
|
|
1115
1519
|
* @param {number=} options.day If positive, adds days. If negative, removes days.
|
|
@@ -1117,7 +1521,7 @@ export function isOverlappingDates(startTimestamp, endTimestamp, firstTimestamp,
|
|
|
1117
1521
|
* @param {number=} options.minute If positive, adds minutes. If negative, removes minutes.
|
|
1118
1522
|
* @param {number=} options.second If positive, adds seconds. If negative, removes seconds.
|
|
1119
1523
|
* @param {number=} options.millisecond If positive, adds milliseconds. If negative, removes milliseconds.
|
|
1120
|
-
* @returns {Timestamp}
|
|
1524
|
+
* @returns {Timestamp} New normalized Timestamp object.
|
|
1121
1525
|
*/
|
|
1122
1526
|
export function addToDate(timestamp, options) {
|
|
1123
1527
|
const ts = cloneTimestamp(timestamp);
|
|
@@ -1146,11 +1550,11 @@ export function addToDate(timestamp, options) {
|
|
|
1146
1550
|
* March. Day and time offsets still use normal JavaScript Date normalization
|
|
1147
1551
|
* after the year/month clamp is applied.
|
|
1148
1552
|
*
|
|
1149
|
-
* This function returns a new frozen
|
|
1553
|
+
* This function returns a new frozen Timestamp; it does not mutate the
|
|
1150
1554
|
* timestamp passed in.
|
|
1151
1555
|
*
|
|
1152
|
-
* @param {Timestamp} timestamp
|
|
1153
|
-
* @param {Object} options
|
|
1556
|
+
* @param {Timestamp} timestamp Timestamp object to offset.
|
|
1557
|
+
* @param {Object} options Date/time units to add or subtract.
|
|
1154
1558
|
* @param {number=} options.year If positive, adds years. If negative, removes years.
|
|
1155
1559
|
* @param {number=} options.month If positive, adds months. If negative, removes month.
|
|
1156
1560
|
* @param {number=} options.day If positive, adds days. If negative, removes days.
|
|
@@ -1158,7 +1562,7 @@ export function addToDate(timestamp, options) {
|
|
|
1158
1562
|
* @param {number=} options.minute If positive, adds minutes. If negative, removes minutes.
|
|
1159
1563
|
* @param {number=} options.second If positive, adds seconds. If negative, removes seconds.
|
|
1160
1564
|
* @param {number=} options.millisecond If positive, adds milliseconds. If negative, removes milliseconds.
|
|
1161
|
-
* @returns {Timestamp}
|
|
1565
|
+
* @returns {Timestamp} New normalized Timestamp object.
|
|
1162
1566
|
*/
|
|
1163
1567
|
export function addToDateClamped(timestamp, options) {
|
|
1164
1568
|
const ts = cloneTimestamp(timestamp);
|
|
@@ -1225,9 +1629,9 @@ function normalizeTimestamp(ts) {
|
|
|
1225
1629
|
return freezeTimestamp(timestamp);
|
|
1226
1630
|
}
|
|
1227
1631
|
/**
|
|
1228
|
-
* Returns number of days between two
|
|
1229
|
-
* @param {Timestamp} ts1 The first
|
|
1230
|
-
* @param {Timestamp} ts2 The second
|
|
1632
|
+
* Returns number of days between two Timestamps
|
|
1633
|
+
* @param {Timestamp} ts1 The first Timestamp
|
|
1634
|
+
* @param {Timestamp} ts2 The second Timestamp
|
|
1231
1635
|
* @returns Number of days
|
|
1232
1636
|
*/
|
|
1233
1637
|
export function daysBetween(ts1, ts2) {
|
|
@@ -1235,9 +1639,9 @@ export function daysBetween(ts1, ts2) {
|
|
|
1235
1639
|
return Math.floor(diff / TIME_CONSTANTS.MILLISECONDS_IN.DAY);
|
|
1236
1640
|
}
|
|
1237
1641
|
/**
|
|
1238
|
-
* Returns number of weeks between two
|
|
1239
|
-
* @param {Timestamp} ts1 The first
|
|
1240
|
-
* @param {Timestamp} ts2 The second
|
|
1642
|
+
* Returns number of weeks between two Timestamps
|
|
1643
|
+
* @param {Timestamp} ts1 The first Timestamp
|
|
1644
|
+
* @param {Timestamp} ts2 The second Timestamp
|
|
1241
1645
|
*/
|
|
1242
1646
|
export function weeksBetween(ts1, ts2) {
|
|
1243
1647
|
let t1 = copyTimestamp(ts1);
|
|
@@ -1246,6 +1650,130 @@ export function weeksBetween(ts1, ts2) {
|
|
|
1246
1650
|
t2 = findWeekday(t2, 6);
|
|
1247
1651
|
return Math.ceil(daysBetween(t1, t2) / TIME_CONSTANTS.DAYS_IN.WEEK);
|
|
1248
1652
|
}
|
|
1653
|
+
/**
|
|
1654
|
+
* Creates a TimestampDuration from signed milliseconds.
|
|
1655
|
+
*
|
|
1656
|
+
* @param {number} milliseconds Signed elapsed milliseconds.
|
|
1657
|
+
* @returns {TimestampDuration} Frozen duration object.
|
|
1658
|
+
*/
|
|
1659
|
+
export function createDuration(milliseconds) {
|
|
1660
|
+
const sign = milliseconds === 0 ? 0 : milliseconds < 0 ? -1 : 1;
|
|
1661
|
+
let remaining = Math.abs(milliseconds);
|
|
1662
|
+
const days = Math.floor(remaining / MILLISECONDS_IN_DAY);
|
|
1663
|
+
remaining -= days * MILLISECONDS_IN_DAY;
|
|
1664
|
+
const hours = Math.floor(remaining / MILLISECONDS_IN_HOUR);
|
|
1665
|
+
remaining -= hours * MILLISECONDS_IN_HOUR;
|
|
1666
|
+
const minutes = Math.floor(remaining / MILLISECONDS_IN_MINUTE);
|
|
1667
|
+
remaining -= minutes * MILLISECONDS_IN_MINUTE;
|
|
1668
|
+
const seconds = Math.floor(remaining / MILLISECONDS_IN_SECOND);
|
|
1669
|
+
remaining -= seconds * MILLISECONDS_IN_SECOND;
|
|
1670
|
+
return Object.freeze({
|
|
1671
|
+
totalMilliseconds: milliseconds,
|
|
1672
|
+
absoluteMilliseconds: Math.abs(milliseconds),
|
|
1673
|
+
sign,
|
|
1674
|
+
days,
|
|
1675
|
+
hours,
|
|
1676
|
+
minutes,
|
|
1677
|
+
seconds,
|
|
1678
|
+
milliseconds: remaining,
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Measures the elapsed duration between two Timestamp values.
|
|
1683
|
+
*
|
|
1684
|
+
* Timestamp fields are read as UTC so the result is deterministic across
|
|
1685
|
+
* server and client runtimes.
|
|
1686
|
+
*
|
|
1687
|
+
* @param {Timestamp} start Start timestamp.
|
|
1688
|
+
* @param {Timestamp} end End timestamp.
|
|
1689
|
+
* @returns {TimestampDuration} Frozen duration object.
|
|
1690
|
+
*/
|
|
1691
|
+
export function durationBetween(start, end) {
|
|
1692
|
+
return createDuration(toUnixMilliseconds(end) - toUnixMilliseconds(start));
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Adds an elapsed duration to a Timestamp.
|
|
1696
|
+
*
|
|
1697
|
+
* This helper treats the Timestamp fields as UTC and returns a Timestamp built
|
|
1698
|
+
* from UTC fields. Use addToDate() for calendar-unit arithmetic such as
|
|
1699
|
+
* "one month from now".
|
|
1700
|
+
*
|
|
1701
|
+
* @param {Timestamp} timestamp Timestamp object to offset.
|
|
1702
|
+
* @param {TimestampDuration | number} duration Duration object or signed milliseconds.
|
|
1703
|
+
* @returns {Timestamp} Offset Timestamp.
|
|
1704
|
+
*/
|
|
1705
|
+
export function addDuration(timestamp, duration) {
|
|
1706
|
+
const milliseconds = typeof duration === "number" ? duration : duration.totalMilliseconds;
|
|
1707
|
+
return fromUnixMilliseconds(toUnixMilliseconds(timestamp) + milliseconds);
|
|
1708
|
+
}
|
|
1709
|
+
/**
|
|
1710
|
+
* Subtracts an elapsed duration from a Timestamp.
|
|
1711
|
+
*
|
|
1712
|
+
* @param {Timestamp} timestamp Timestamp object to offset.
|
|
1713
|
+
* @param {TimestampDuration | number} duration Duration object or signed milliseconds.
|
|
1714
|
+
* @returns {Timestamp} Offset Timestamp.
|
|
1715
|
+
*/
|
|
1716
|
+
export function subtractDuration(timestamp, duration) {
|
|
1717
|
+
const milliseconds = typeof duration === "number" ? duration : duration.totalMilliseconds;
|
|
1718
|
+
return addDuration(timestamp, -milliseconds);
|
|
1719
|
+
}
|
|
1720
|
+
/**
|
|
1721
|
+
* Formats a duration as `HH:mm:ss` or `HH:mm:ss.SSS`.
|
|
1722
|
+
*
|
|
1723
|
+
* Hours include full days, so a two-day duration formats as `48:00:00`.
|
|
1724
|
+
*
|
|
1725
|
+
* @param {TimestampDuration | number} duration Duration object or signed milliseconds.
|
|
1726
|
+
* @param {FormatDurationOptions=} options Formatting options.
|
|
1727
|
+
* @returns {string} Formatted duration.
|
|
1728
|
+
*/
|
|
1729
|
+
export function formatDuration(duration, options = {}) {
|
|
1730
|
+
const value = typeof duration === "number" ? createDuration(duration) : duration;
|
|
1731
|
+
const hours = value.days * HOURS_IN_DAY + value.hours;
|
|
1732
|
+
const sign = options.signed === true && value.sign < 0 ? "-" : "";
|
|
1733
|
+
let formatted = `${sign}${padNumber(hours, 2)}:${padNumber(value.minutes, 2)}:${padNumber(value.seconds, 2)}`;
|
|
1734
|
+
if (options.milliseconds === true) {
|
|
1735
|
+
formatted += `.${padNumber(value.milliseconds, 3)}`;
|
|
1736
|
+
}
|
|
1737
|
+
return formatted;
|
|
1738
|
+
}
|
|
1739
|
+
function roundTimestampToInterval(timestamp, minutes, rounder) {
|
|
1740
|
+
if (minutes <= 0 || Number.isFinite(minutes) === false) {
|
|
1741
|
+
return copyTimestamp(timestamp);
|
|
1742
|
+
}
|
|
1743
|
+
const interval = minutes * MILLISECONDS_IN_MINUTE;
|
|
1744
|
+
const value = toUnixMilliseconds(timestamp);
|
|
1745
|
+
return fromUnixMilliseconds(rounder(value / interval) * interval);
|
|
1746
|
+
}
|
|
1747
|
+
/**
|
|
1748
|
+
* Floors a Timestamp down to the nearest interval.
|
|
1749
|
+
*
|
|
1750
|
+
* @param {Timestamp} timestamp Timestamp object to round.
|
|
1751
|
+
* @param {number} minutes Interval size in minutes.
|
|
1752
|
+
* @returns {Timestamp} Rounded Timestamp.
|
|
1753
|
+
*/
|
|
1754
|
+
export function floorToInterval(timestamp, minutes) {
|
|
1755
|
+
return roundTimestampToInterval(timestamp, minutes, Math.floor);
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Ceils a Timestamp up to the nearest interval.
|
|
1759
|
+
*
|
|
1760
|
+
* @param {Timestamp} timestamp Timestamp object to round.
|
|
1761
|
+
* @param {number} minutes Interval size in minutes.
|
|
1762
|
+
* @returns {Timestamp} Rounded Timestamp.
|
|
1763
|
+
*/
|
|
1764
|
+
export function ceilToInterval(timestamp, minutes) {
|
|
1765
|
+
return roundTimestampToInterval(timestamp, minutes, Math.ceil);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Rounds a Timestamp to the nearest interval.
|
|
1769
|
+
*
|
|
1770
|
+
* @param {Timestamp} timestamp Timestamp object to round.
|
|
1771
|
+
* @param {number} minutes Interval size in minutes.
|
|
1772
|
+
* @returns {Timestamp} Rounded Timestamp.
|
|
1773
|
+
*/
|
|
1774
|
+
export function roundToInterval(timestamp, minutes) {
|
|
1775
|
+
return roundTimestampToInterval(timestamp, minutes, Math.round);
|
|
1776
|
+
}
|
|
1249
1777
|
// Known dates
|
|
1250
1778
|
const weekdayDateMap = {
|
|
1251
1779
|
Sun: new Date("2020-01-05T00:00:00.000Z"),
|
|
@@ -1286,7 +1814,6 @@ export function getWeekdayFormatter() {
|
|
|
1286
1814
|
short: { timeZone: "UTC", weekday: "short" },
|
|
1287
1815
|
narrow: { timeZone: "UTC", weekday: "narrow" },
|
|
1288
1816
|
};
|
|
1289
|
-
/* istanbul ignore next */
|
|
1290
1817
|
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") {
|
|
1291
1818
|
return emptyFormatter;
|
|
1292
1819
|
}
|
|
@@ -1303,7 +1830,7 @@ export function getWeekdayFormatter() {
|
|
|
1303
1830
|
const intlFormatter = new Intl.DateTimeFormat(locale || undefined, resolveIntlNameFormat(options, type));
|
|
1304
1831
|
return intlFormatter.format(weekdayDateMap[weekday]);
|
|
1305
1832
|
}
|
|
1306
|
-
catch (e)
|
|
1833
|
+
catch (e) {
|
|
1307
1834
|
if (e instanceof Error) {
|
|
1308
1835
|
console.error(`Intl.DateTimeFormat: ${e.message} -> day of week: ${weekday}`);
|
|
1309
1836
|
}
|
|
@@ -1313,11 +1840,11 @@ export function getWeekdayFormatter() {
|
|
|
1313
1840
|
return weekdayFormatter;
|
|
1314
1841
|
}
|
|
1315
1842
|
/**
|
|
1316
|
-
* Retrieves
|
|
1843
|
+
* Retrieves localized weekday names.
|
|
1317
1844
|
*
|
|
1318
|
-
* @param {string} type
|
|
1319
|
-
* @param {string}
|
|
1320
|
-
* @returns {string[]}
|
|
1845
|
+
* @param {string} type Format type: `narrow`, `short`, or `long`.
|
|
1846
|
+
* @param {string} locale Locale to use for formatting, such as `en-US`.
|
|
1847
|
+
* @returns {string[]} Localized weekday names in Sunday-first order.
|
|
1321
1848
|
*/
|
|
1322
1849
|
export function getWeekdayNames(type, locale) {
|
|
1323
1850
|
const shortWeekdays = Object.keys(weekdayDateMap);
|
|
@@ -1343,7 +1870,6 @@ export function getMonthFormatter() {
|
|
|
1343
1870
|
short: { timeZone: "UTC", month: "short" },
|
|
1344
1871
|
narrow: { timeZone: "UTC", month: "narrow" },
|
|
1345
1872
|
};
|
|
1346
|
-
/* istanbul ignore next */
|
|
1347
1873
|
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") {
|
|
1348
1874
|
return emptyFormatter;
|
|
1349
1875
|
}
|
|
@@ -1363,7 +1889,7 @@ export function getMonthFormatter() {
|
|
|
1363
1889
|
date.setMonth(month);
|
|
1364
1890
|
return intlFormatter.format(date);
|
|
1365
1891
|
}
|
|
1366
|
-
catch (e)
|
|
1892
|
+
catch (e) {
|
|
1367
1893
|
if (e instanceof Error) {
|
|
1368
1894
|
console.error(`Intl.DateTimeFormat: ${e.message} -> month: ${month}`);
|
|
1369
1895
|
}
|
|
@@ -1373,94 +1899,14 @@ export function getMonthFormatter() {
|
|
|
1373
1899
|
return monthFormatter;
|
|
1374
1900
|
}
|
|
1375
1901
|
/**
|
|
1376
|
-
* Retrieves
|
|
1902
|
+
* Retrieves localized month names.
|
|
1377
1903
|
*
|
|
1378
|
-
* @param {string} type
|
|
1379
|
-
* @param {string}
|
|
1380
|
-
* @returns {string[]}
|
|
1904
|
+
* @param {string} type Format type: `narrow`, `short`, or `long`.
|
|
1905
|
+
* @param {string} locale Locale to use for formatting, such as `en-US`.
|
|
1906
|
+
* @returns {string[]} Localized month names in January-first order.
|
|
1381
1907
|
*/
|
|
1382
1908
|
export function getMonthNames(type, locale) {
|
|
1383
1909
|
const monthFormatter = getMonthFormatter();
|
|
1384
1910
|
return [...Array(12).keys()].map((month) => monthFormatter(month, type, locale));
|
|
1385
1911
|
}
|
|
1386
|
-
// the exports...
|
|
1387
|
-
export default {
|
|
1388
|
-
PARSE_DATETIME,
|
|
1389
|
-
PARSE_DATE,
|
|
1390
|
-
PARSE_TIME,
|
|
1391
|
-
DAYS_IN_MONTH,
|
|
1392
|
-
DAYS_IN_MONTH_LEAP,
|
|
1393
|
-
DAYS_IN_MONTH_MIN,
|
|
1394
|
-
DAYS_IN_MONTH_MAX,
|
|
1395
|
-
MONTH_MAX,
|
|
1396
|
-
MONTH_MIN,
|
|
1397
|
-
DAY_MIN,
|
|
1398
|
-
TIME_CONSTANTS,
|
|
1399
|
-
DAYS_IN_WEEK,
|
|
1400
|
-
MINUTES_IN_HOUR,
|
|
1401
|
-
HOURS_IN_DAY,
|
|
1402
|
-
FIRST_HOUR,
|
|
1403
|
-
MILLISECONDS_IN_MINUTE,
|
|
1404
|
-
MILLISECONDS_IN_HOUR,
|
|
1405
|
-
MILLISECONDS_IN_DAY,
|
|
1406
|
-
MILLISECONDS_IN_WEEK,
|
|
1407
|
-
Timestamp,
|
|
1408
|
-
TimeObject,
|
|
1409
|
-
today,
|
|
1410
|
-
getStartOfWeek,
|
|
1411
|
-
getEndOfWeek,
|
|
1412
|
-
getStartOfMonth,
|
|
1413
|
-
getEndOfMonth,
|
|
1414
|
-
parseTime,
|
|
1415
|
-
validateTimestamp,
|
|
1416
|
-
parsed,
|
|
1417
|
-
parseTimestamp,
|
|
1418
|
-
parseDate,
|
|
1419
|
-
getDayIdentifier,
|
|
1420
|
-
getTimeIdentifier,
|
|
1421
|
-
getDayTimeIdentifier,
|
|
1422
|
-
diffTimestamp,
|
|
1423
|
-
updateRelative,
|
|
1424
|
-
updateMinutes,
|
|
1425
|
-
updateWeekday,
|
|
1426
|
-
updateDayOfYear,
|
|
1427
|
-
updateWorkWeek,
|
|
1428
|
-
updateDisabled,
|
|
1429
|
-
updateFormatted,
|
|
1430
|
-
getDayOfYear,
|
|
1431
|
-
getWorkWeek,
|
|
1432
|
-
getWeekday,
|
|
1433
|
-
isLeapYear,
|
|
1434
|
-
daysInMonth,
|
|
1435
|
-
copyTimestamp,
|
|
1436
|
-
padNumber,
|
|
1437
|
-
getDate,
|
|
1438
|
-
getTime,
|
|
1439
|
-
getDateTime,
|
|
1440
|
-
nextDay,
|
|
1441
|
-
prevDay,
|
|
1442
|
-
relativeDays,
|
|
1443
|
-
findWeekday,
|
|
1444
|
-
createDayList,
|
|
1445
|
-
createIntervalList,
|
|
1446
|
-
createNativeLocaleFormatter,
|
|
1447
|
-
makeDate,
|
|
1448
|
-
makeDateTime,
|
|
1449
|
-
getDateObject,
|
|
1450
|
-
validateNumber,
|
|
1451
|
-
isBetweenDates,
|
|
1452
|
-
isOverlappingDates,
|
|
1453
|
-
daysBetween,
|
|
1454
|
-
weeksBetween,
|
|
1455
|
-
addToDate,
|
|
1456
|
-
addToDateClamped,
|
|
1457
|
-
compareTimestamps,
|
|
1458
|
-
compareDate,
|
|
1459
|
-
compareTime,
|
|
1460
|
-
compareDateTime,
|
|
1461
|
-
getWeekdayFormatter,
|
|
1462
|
-
getWeekdayNames,
|
|
1463
|
-
getMonthFormatter,
|
|
1464
|
-
getMonthNames,
|
|
1465
|
-
};
|
|
1466
1912
|
//# sourceMappingURL=index.js.map
|