@prairielearn/formatter 1.4.0 → 1.4.2
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/CHANGELOG.md +12 -0
- package/dist/date.d.ts +8 -2
- package/dist/date.js +55 -14
- package/dist/date.js.map +1 -1
- package/dist/date.test.js +281 -78
- package/dist/date.test.js.map +1 -1
- package/package.json +5 -5
- package/src/date.test.ts +408 -121
- package/src/date.ts +74 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @prairielearn/formatter
|
|
2
2
|
|
|
3
|
+
## 1.4.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7f25a8a: Add `maxPrecision` and `minPrecision` options to `format*Friendly` functions.
|
|
8
|
+
|
|
9
|
+
## 1.4.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 678b48a: Upgrade all JavaScript dependencies
|
|
14
|
+
|
|
3
15
|
## 1.4.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/date.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
type TimePrecision = 'hour' | 'minute' | 'second';
|
|
1
2
|
/**
|
|
2
3
|
* Format a date to a human-readable string like '2020-03-27T12:34:56 (CDT)'.
|
|
3
4
|
*
|
|
@@ -78,14 +79,18 @@ export declare function formatDateWithinRange(date: Date, rangeStart: Date, rang
|
|
|
78
79
|
* @param param.timeFirst If true, the time is shown before the date (default false).
|
|
79
80
|
* @param param.dateOnly If true, only the date is shown (default false).
|
|
80
81
|
* @param param.timeOnly If true, only the time is shown (default false).
|
|
82
|
+
* @param param.maxPrecision The maximum precision to show for time (default 'minute').
|
|
83
|
+
* @param param.minPrecision The minimum precision to always show for time (default 'hour').
|
|
81
84
|
* @returns Human-readable string representing the date and time.
|
|
82
85
|
*/
|
|
83
|
-
export declare function formatDateFriendly(date: Date, timezone: string, { baseDate, includeTz, timeFirst, dateOnly, timeOnly, }?: {
|
|
86
|
+
export declare function formatDateFriendly(date: Date, timezone: string, { baseDate, includeTz, timeFirst, dateOnly, timeOnly, maxPrecision, minPrecision, }?: {
|
|
84
87
|
baseDate?: Date;
|
|
85
88
|
includeTz?: boolean;
|
|
86
89
|
timeFirst?: boolean;
|
|
87
90
|
dateOnly?: boolean;
|
|
88
91
|
timeOnly?: boolean;
|
|
92
|
+
maxPrecision?: TimePrecision;
|
|
93
|
+
minPrecision?: TimePrecision;
|
|
89
94
|
}): string;
|
|
90
95
|
/**
|
|
91
96
|
* Format a datetime range to a string like:
|
|
@@ -104,4 +109,5 @@ export declare function formatDateFriendly(date: Date, timezone: string, { baseD
|
|
|
104
109
|
* @param options Additional options for formatting the displayed date, taken from `formatDateFriendlyString()`.
|
|
105
110
|
* @returns Human-readable string representing the datetime range.
|
|
106
111
|
*/
|
|
107
|
-
export declare function formatDateRangeFriendly(start: Date, end: Date, timezone: string, { baseDate, includeTz, timeFirst, dateOnly, }?: Parameters<typeof formatDateFriendly>[2]): string;
|
|
112
|
+
export declare function formatDateRangeFriendly(start: Date, end: Date, timezone: string, { baseDate, includeTz, timeFirst, dateOnly, maxPrecision, minPrecision, }?: Parameters<typeof formatDateFriendly>[2]): string;
|
|
113
|
+
export {};
|
package/dist/date.js
CHANGED
|
@@ -173,11 +173,16 @@ export function formatDateWithinRange(date, rangeStart, rangeEnd, timeZone) {
|
|
|
173
173
|
* - '3:34pm'
|
|
174
174
|
* - '3:34:17pm'
|
|
175
175
|
*
|
|
176
|
+
* maxPrecision must be an equal or smaller unit than minPrecision.
|
|
177
|
+
*
|
|
176
178
|
* @param date The date to format.
|
|
177
179
|
* @param timezone The time zone to use for formatting.
|
|
178
180
|
* @param baseDate The base date to use for comparison.
|
|
181
|
+
* @param maxPrecision Only show units as large or larger than the max precision.
|
|
182
|
+
* @param minPrecision Always show that unit and larger, potentially showing smaller units.
|
|
183
|
+
*
|
|
179
184
|
*/
|
|
180
|
-
function formatDateFriendlyParts(date, timezone, baseDate) {
|
|
185
|
+
function formatDateFriendlyParts(date, timezone, baseDate, maxPrecision = 'second', minPrecision = 'hour') {
|
|
181
186
|
// compute the number of days from the base date (0 = today, 1 = tomorrow, etc.)
|
|
182
187
|
const baseZonedDateTime = toTemporalInstant.call(baseDate).toZonedDateTimeISO(timezone);
|
|
183
188
|
const zonedDateTime = toTemporalInstant.call(date).toZonedDateTimeISO(timezone);
|
|
@@ -216,16 +221,50 @@ function formatDateFriendlyParts(date, timezone, baseDate) {
|
|
|
216
221
|
else {
|
|
217
222
|
dateFormatted = `${parts.weekday.value}, ${parts.month.value}\u00a0${parts.day.value}, ${parts.year.value}`;
|
|
218
223
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
224
|
+
const precisionOrder = ['second', 'minute', 'hour'];
|
|
225
|
+
const maxIndex = precisionOrder.indexOf(maxPrecision);
|
|
226
|
+
const minIndex = precisionOrder.indexOf(minPrecision);
|
|
227
|
+
/**
|
|
228
|
+
* The maximum precision must be a unit smaller than or equal to the minimum precision, otherwise the rules will contradict each other.
|
|
229
|
+
*
|
|
230
|
+
* If max is a larger unit than min, e.g. max = hour, min = minute, then by "min"
|
|
231
|
+
* we must display minute and smaller but by "max" we can display hour and larger, which is a contradiction.
|
|
232
|
+
*
|
|
233
|
+
* If min is a larger unit than max, e.g. max = minute, min = hour, then by "min" we must display
|
|
234
|
+
* hour and smaller and by "max" we can display minutes and larger. These do not contradict each other.
|
|
235
|
+
*
|
|
236
|
+
* V min/max > | h | m | s
|
|
237
|
+
* h | X | X | X
|
|
238
|
+
* m | I | X | X
|
|
239
|
+
* s | I | I | X
|
|
240
|
+
*
|
|
241
|
+
* X - valid configuration
|
|
242
|
+
* I - invalid configuration
|
|
243
|
+
*/
|
|
244
|
+
// A higher index corresponds to a larger unit, so if maxIndex is larger than minIndex, then the rules contradict each other.
|
|
245
|
+
if (maxIndex > minIndex) {
|
|
246
|
+
throw new Error('maxPrecision must be an equal or smaller unit than minPrecision.');
|
|
223
247
|
}
|
|
224
|
-
|
|
225
|
-
|
|
248
|
+
/** Examples:
|
|
249
|
+
* min=h, max=h: 0:00:00AM -> 0AM, 0:00:01AM -> 0AM, 0:01:01AM -> 0AM
|
|
250
|
+
* min=h, max=m: 0:00:00AM -> 0AM, 0:00:01AM -> 0AM, 0:01:01AM -> 0:01AM
|
|
251
|
+
* min=h, max=s: 0:00:00AM -> 0AM, 0:00:01AM -> 0:00:01AM, 0:01:01AM -> 0:01:01AM
|
|
252
|
+
*
|
|
253
|
+
* min=m, max=m: 0:00:00AM -> 0:00AM, 0:00:01AM -> 0:00AM, 0:01:01AM -> 0:00AM
|
|
254
|
+
* min=m, max=s: 0:00:00AM -> 0:00AM, 0:00:01AM -> 0:00AM, 0:01:01AM -> 0:01:01AM
|
|
255
|
+
*
|
|
256
|
+
* min=s, max=s: 0:00:00AM -> 0:00:00AM, 0:00:01AM -> 0:00:01AM, 0:01:01AM -> 0:01:01AM
|
|
257
|
+
*/
|
|
258
|
+
let timeFormatted = parts.hour.value;
|
|
259
|
+
const shouldShowMinutes = ['minute', 'second'].includes(minPrecision) ||
|
|
260
|
+
(maxPrecision === 'minute' && parts.minute.value !== '00') ||
|
|
261
|
+
(maxPrecision === 'second' && (parts.minute.value !== '00' || parts.second.value !== '00'));
|
|
262
|
+
if (shouldShowMinutes) {
|
|
263
|
+
timeFormatted += `:${parts.minute.value}`;
|
|
226
264
|
}
|
|
227
|
-
|
|
228
|
-
|
|
265
|
+
const shouldShowSeconds = minPrecision === 'second' || (maxPrecision === 'second' && parts.second.value !== '00');
|
|
266
|
+
if (shouldShowSeconds) {
|
|
267
|
+
timeFormatted += `:${parts.second.value}`;
|
|
229
268
|
}
|
|
230
269
|
// add the am/pm part
|
|
231
270
|
timeFormatted = `${timeFormatted}${parts.dayPeriod.value.toLowerCase()}`;
|
|
@@ -258,10 +297,12 @@ function formatDateFriendlyParts(date, timezone, baseDate) {
|
|
|
258
297
|
* @param param.timeFirst If true, the time is shown before the date (default false).
|
|
259
298
|
* @param param.dateOnly If true, only the date is shown (default false).
|
|
260
299
|
* @param param.timeOnly If true, only the time is shown (default false).
|
|
300
|
+
* @param param.maxPrecision The maximum precision to show for time (default 'minute').
|
|
301
|
+
* @param param.minPrecision The minimum precision to always show for time (default 'hour').
|
|
261
302
|
* @returns Human-readable string representing the date and time.
|
|
262
303
|
*/
|
|
263
|
-
export function formatDateFriendly(date, timezone, { baseDate = new Date(), includeTz = true, timeFirst = false, dateOnly = false, timeOnly = false, } = {}) {
|
|
264
|
-
const { dateFormatted, timeFormatted, timezoneFormatted } = formatDateFriendlyParts(date, timezone, baseDate);
|
|
304
|
+
export function formatDateFriendly(date, timezone, { baseDate = new Date(), includeTz = true, timeFirst = false, dateOnly = false, timeOnly = false, maxPrecision = 'second', minPrecision = 'hour', } = {}) {
|
|
305
|
+
const { dateFormatted, timeFormatted, timezoneFormatted } = formatDateFriendlyParts(date, timezone, baseDate, maxPrecision, minPrecision);
|
|
265
306
|
let dateTimeFormatted = '';
|
|
266
307
|
if (dateOnly) {
|
|
267
308
|
dateTimeFormatted = dateFormatted;
|
|
@@ -299,9 +340,9 @@ export function formatDateFriendly(date, timezone, { baseDate = new Date(), incl
|
|
|
299
340
|
* @param options Additional options for formatting the displayed date, taken from `formatDateFriendlyString()`.
|
|
300
341
|
* @returns Human-readable string representing the datetime range.
|
|
301
342
|
*/
|
|
302
|
-
export function formatDateRangeFriendly(start, end, timezone, { baseDate = new Date(), includeTz = true, timeFirst = false, dateOnly = false, } = {}) {
|
|
303
|
-
const { dateFormatted: startDateFormatted, timeFormatted: startTimeFormatted, timezoneFormatted, } = formatDateFriendlyParts(start, timezone, baseDate);
|
|
304
|
-
const { dateFormatted: endDateFormatted, timeFormatted: endTimeFormatted } = formatDateFriendlyParts(end, timezone, baseDate);
|
|
343
|
+
export function formatDateRangeFriendly(start, end, timezone, { baseDate = new Date(), includeTz = true, timeFirst = false, dateOnly = false, maxPrecision = 'second', minPrecision = 'hour', } = {}) {
|
|
344
|
+
const { dateFormatted: startDateFormatted, timeFormatted: startTimeFormatted, timezoneFormatted, } = formatDateFriendlyParts(start, timezone, baseDate, maxPrecision, minPrecision);
|
|
345
|
+
const { dateFormatted: endDateFormatted, timeFormatted: endTimeFormatted } = formatDateFriendlyParts(end, timezone, baseDate, maxPrecision, minPrecision);
|
|
305
346
|
let result;
|
|
306
347
|
if (dateOnly) {
|
|
307
348
|
if (startDateFormatted === endDateFormatted) {
|
package/dist/date.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"date.js","sourceRoot":"","sources":["../src/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAEpC;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,IAAU,EACV,QAAgB,EAChB,EACE,SAAS,GAAG,IAAI,EAChB,MAAM,GAAG,KAAK,EACd,SAAS,GAAG,KAAK,MACiD,EAAE;IAEtE,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,sBAAsB,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACjD,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;KACxC,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAClJ,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IACnE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,QAAgB;IACxD,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;KACf,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,QAAgB;IAC1D,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KAClB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC7C,QAAQ;QACR,YAAY,EAAE,OAAO;KACtB,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAU,EACV,QAAgB,EAChB,EAAE,SAAS,GAAG,IAAI,KAA8B,EAAE;IAElD,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtF,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IACnE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAU,EACV,UAAgB,EAChB,QAAc,EACd,QAAgB;IAEhB,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CACrB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAC7D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,EACnE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CACpB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,EACjE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IAEF,mCAAmC;IACnC,MAAM,OAAO,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1F,MAAM,QAAQ,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAC9F,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAEtF,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC/C,2DAA2D;QAC3D,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED,4CAA4C;IAC5C,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAEtC,uEAAuE;IACvE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,OAAO,GAA+B;YAC1C,QAAQ;YACR,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;SAClB,CAAC;QACF,MAAM,SAAS,GAAG,KAAK,CACrB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAC7D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;QACF,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC9G,CAAC;IAED,6BAA6B;IAC7B,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACrI,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,uBAAuB,CAC9B,IAAU,EACV,QAAgB,EAChB,QAAc;IAEd,gFAAgF;IAEhF,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACxF,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAEhF,MAAM,aAAa,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAE9C,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC;IAE/E,wCAAwC;IAExC,MAAM,OAAO,GAA+B;QAC1C,QAAQ,EAAE,QAAQ;QAClB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAElG,yBAAyB;IAEzB,IAAI,aAAa,GAAG,EAAE,CAAC;IACvB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,aAAa,GAAG,OAAO,CAAC;IAC1B,CAAC;SAAM,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QAC5B,aAAa,GAAG,UAAU,CAAC;IAC7B,CAAC;SAAM,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QAC7B,aAAa,GAAG,WAAW,CAAC;IAC9B,CAAC;SAAM,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,EAAE,CAAC;QACvC,gEAAgE;QAChE,aAAa,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACzF,CAAC;SAAM,CAAC;QACN,aAAa,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC9G,CAAC;IAED,yBAAyB;IAEzB,IAAI,aAAa,GAAG,EAAE,CAAC;IACvB,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QAC/D,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACxC,CAAC;SAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;QACvC,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACpF,CAAC;IACD,qBAAqB;IACrB,aAAa,GAAG,GAAG,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;IAEzE,sBAAsB;IAEtB,MAAM,iBAAiB,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IAE1D,OAAO;QACL,aAAa;QACb,aAAa;QACb,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAU,EACV,QAAgB,EAChB,EACE,QAAQ,GAAG,IAAI,IAAI,EAAE,EACrB,SAAS,GAAG,IAAI,EAChB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,MAOd,EAAE;IAEN,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,uBAAuB,CACjF,IAAI,EACJ,QAAQ,EACR,QAAQ,CACT,CAAC;IAEF,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAC3B,IAAI,QAAQ,EAAE,CAAC;QACb,iBAAiB,GAAG,aAAa,CAAC;IACpC,CAAC;SAAM,IAAI,QAAQ,EAAE,CAAC;QACpB,iBAAiB,GAAG,aAAa,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,IAAI,SAAS,EAAE,CAAC;YACd,iBAAiB,GAAG,GAAG,aAAa,IAAI,aAAa,EAAE,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,GAAG,aAAa,KAAK,aAAa,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,iBAAiB,GAAG,GAAG,iBAAiB,IAAI,iBAAiB,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAW,EACX,GAAS,EACT,QAAgB,EAChB,EACE,QAAQ,GAAG,IAAI,IAAI,EAAE,EACrB,SAAS,GAAG,IAAI,EAChB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,MAC4B,EAAE;IAEhD,MAAM,EACJ,aAAa,EAAE,kBAAkB,EACjC,aAAa,EAAE,kBAAkB,EACjC,iBAAiB,GAClB,GAAG,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,GACxE,uBAAuB,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAEnD,IAAI,MAA0B,CAAC;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;YAC5C,MAAM,GAAG,kBAAkB,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,kBAAkB,OAAO,gBAAgB,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;YAC5C,IAAI,kBAAsC,CAAC;YAC3C,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;gBAC5C,kBAAkB,GAAG,kBAAkB,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,kBAAkB,GAAG,GAAG,kBAAkB,OAAO,gBAAgB,EAAE,CAAC;YACtE,CAAC;YACD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,EAAE,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,kBAAkB,KAAK,kBAAkB,EAAE,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,OAAO,gBAAgB,IAAI,gBAAgB,EAAE,CAAC;YACpG,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,kBAAkB,KAAK,kBAAkB,OAAO,gBAAgB,KAAK,gBAAgB,EAAE,CAAC;YACtG,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,MAAM,IAAI,iBAAiB,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { toTemporalInstant } from '@js-temporal/polyfill';\nimport keyBy from 'lodash/keyBy.js';\n\n/**\n * Format a date to a human-readable string like '2020-03-27T12:34:56 (CDT)'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @param param2.includeTz Whether to include the time zone in the output (default true).\n * @param param2.longTz Whether to use the long time zone name (default false).\n * @returns Human-readable string representing the date.\n */\nexport function formatDate(\n date: Date,\n timeZone: string,\n {\n includeTz = true,\n longTz = false,\n includeMs = false,\n }: { includeTz?: boolean; longTz?: boolean; includeMs?: boolean } = {},\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: includeMs ? 3 : undefined,\n timeZoneName: longTz ? 'long' : 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n let dateFormatted = `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n if (includeMs) {\n dateFormatted = `${dateFormatted}.${parts.fractionalSecond.value}`;\n }\n if (includeTz) {\n dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;\n }\n return dateFormatted;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMD(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value}`;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27 14:27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMDHM(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}`;\n}\n\n/**\n * Format a time zone to a human-readable string like 'CDT'.\n *\n * @param timeZone The time zone to format.\n * @returns Human-readable string representing the time zone.\n */\nexport function formatTz(timeZone: string): string {\n const date = new Date();\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone,\n timeZoneName: 'short',\n }).formatToParts(date);\n const tz = parts.find((p) => p.type === 'timeZoneName');\n return tz ? tz.value : timeZone;\n}\n\n/**\n * Format a date to a human-readable string like '14:27:00 (CDT)'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @param param2.includeTz Whether to include the time zone in the output (default true).\n * @returns Human-readable string representing the date.\n */\nexport function formatDateHMS(\n date: Date,\n timeZone: string,\n { includeTz = true }: { includeTz?: boolean } = {},\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n timeZoneName: 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n let dateFormatted = `${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n if (includeTz) {\n dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;\n }\n return dateFormatted;\n}\n\n/**\n * Format a date to a human-readable string like '18:23' or 'May 2, 07:12',\n * where the precision is determined by the range.\n *\n * @param date The date to format.\n * @param rangeStart The start of the range.\n * @param rangeEnd The end of the range.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateWithinRange(\n date: Date,\n rangeStart: Date,\n rangeEnd: Date,\n timeZone: string,\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n timeZoneName: 'short',\n };\n const dateParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(date),\n (x) => x.type,\n );\n const startParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(rangeStart),\n (x) => x.type,\n );\n const endParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(rangeEnd),\n (x) => x.type,\n );\n\n // format the date (not time) parts\n const dateYMD = `${dateParts.year.value}-${dateParts.month.value}-${dateParts.day.value}`;\n const startYMD = `${startParts.year.value}-${startParts.month.value}-${startParts.day.value}`;\n const endYMD = `${endParts.year.value}-${endParts.month.value}-${endParts.day.value}`;\n\n if (dateYMD === startYMD && dateYMD === endYMD) {\n // only show the time if the date is the same for all three\n return `${dateParts.hour.value}:${dateParts.minute.value}`;\n }\n\n // format the year, but not the month or day\n const dateY = `${dateParts.year.value}`;\n const startY = `${startParts.year.value}`;\n const endY = `${endParts.year.value}`;\n\n // if the year is the same for all three, show the month, day, and time\n if (dateY === startY && dateY === endY) {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n };\n const dateParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(date),\n (x) => x.type,\n );\n return `${dateParts.month.value} ${dateParts.day.value}, ${dateParts.hour.value}:${dateParts.minute.value}`;\n }\n\n // fall back to the full date\n return `${dateParts.year.value}-${dateParts.month.value}-${dateParts.day.value} ${dateParts.hour.value}:${dateParts.minute.value}`;\n}\n\n/**\n * Format a Date to date and time strings in the given time zone. The date is\n * formatted like\n * - 'today'\n * - 'Mon, Mar 20' (if within 180 days of the base date)\n * - 'Wed, Jan 1, 2020'\n *\n * The time format leaves off zero minutes and seconds, and uses 12-hour time,\n * giving strings like\n * - '3pm'\n * - '3:34pm'\n * - '3:34:17pm'\n *\n * @param date The date to format.\n * @param timezone The time zone to use for formatting.\n * @param baseDate The base date to use for comparison.\n */\nfunction formatDateFriendlyParts(\n date: Date,\n timezone: string,\n baseDate: Date,\n): { dateFormatted: string; timeFormatted: string; timezoneFormatted: string } {\n // compute the number of days from the base date (0 = today, 1 = tomorrow, etc.)\n\n const baseZonedDateTime = toTemporalInstant.call(baseDate).toZonedDateTimeISO(timezone);\n const zonedDateTime = toTemporalInstant.call(date).toZonedDateTimeISO(timezone);\n\n const basePlainDate = baseZonedDateTime.toPlainDate();\n const plainDate = zonedDateTime.toPlainDate();\n\n const daysOffset = plainDate.since(basePlainDate, { largestUnit: 'day' }).days;\n\n // format the parts of the date and time\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: timezone,\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n weekday: 'short',\n hourCycle: 'h12',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n timeZoneName: 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n\n // format the date string\n\n let dateFormatted = '';\n if (daysOffset === 0) {\n dateFormatted = 'today';\n } else if (daysOffset === 1) {\n dateFormatted = 'tomorrow';\n } else if (daysOffset === -1) {\n dateFormatted = 'yesterday';\n } else if (Math.abs(daysOffset) <= 180) {\n // non-breaking-space (\\u00a0) is used between the month and day\n dateFormatted = `${parts.weekday.value}, ${parts.month.value}\\u00a0${parts.day.value}`;\n } else {\n dateFormatted = `${parts.weekday.value}, ${parts.month.value}\\u00a0${parts.day.value}, ${parts.year.value}`;\n }\n\n // format the time string\n\n let timeFormatted = '';\n if (parts.minute.value === '00' && parts.second.value === '00') {\n timeFormatted = `${parts.hour.value}`;\n } else if (parts.second.value === '00') {\n timeFormatted = `${parts.hour.value}:${parts.minute.value}`;\n } else {\n timeFormatted = `${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n }\n // add the am/pm part\n timeFormatted = `${timeFormatted}${parts.dayPeriod.value.toLowerCase()}`;\n\n // format the timezone\n\n const timezoneFormatted = `(${parts.timeZoneName.value})`;\n\n return {\n dateFormatted,\n timeFormatted,\n timezoneFormatted,\n };\n}\n\n/**\n * Format a date to a string like:\n * - 'today, 3pm'\n * - 'tomorrow, 10:30am'\n * - 'yesterday, 11:45pm'\n * - 'Mon, Mar 20, 8:15am' (if within 180 days of the base date)\n * - 'Wed, Jan 1, 2020, 12pm'\n * - `today, 3pm (CDT)` (if `includeTz` is true)\n * - `3pm today` (if `timeFirst` is true)\n * - 'today' (if `dateOnly` is true)\n *\n * If using this within a sentence like `... at ${formatDateFriendlyString()}`,\n * use `timeFirst: true` to improve readability.\n *\n * @param date The date to format.\n * @param timezone The time zone to use for formatting.\n * @param param.baseDate The base date to use for comparison (default is the current date).\n * @param param.includeTz Whether to include the time zone in the output (default true).\n * @param param.timeFirst If true, the time is shown before the date (default false).\n * @param param.dateOnly If true, only the date is shown (default false).\n * @param param.timeOnly If true, only the time is shown (default false).\n * @returns Human-readable string representing the date and time.\n */\nexport function formatDateFriendly(\n date: Date,\n timezone: string,\n {\n baseDate = new Date(),\n includeTz = true,\n timeFirst = false,\n dateOnly = false,\n timeOnly = false,\n }: {\n baseDate?: Date;\n includeTz?: boolean;\n timeFirst?: boolean;\n dateOnly?: boolean;\n timeOnly?: boolean;\n } = {},\n): string {\n const { dateFormatted, timeFormatted, timezoneFormatted } = formatDateFriendlyParts(\n date,\n timezone,\n baseDate,\n );\n\n let dateTimeFormatted = '';\n if (dateOnly) {\n dateTimeFormatted = dateFormatted;\n } else if (timeOnly) {\n dateTimeFormatted = timeFormatted;\n } else {\n if (timeFirst) {\n dateTimeFormatted = `${timeFormatted} ${dateFormatted}`;\n } else {\n dateTimeFormatted = `${dateFormatted}, ${timeFormatted}`;\n }\n }\n if (includeTz) {\n dateTimeFormatted = `${dateTimeFormatted} ${timezoneFormatted}`;\n }\n return dateTimeFormatted;\n}\n\n/**\n * Format a datetime range to a string like:\n * - 'today, 10am'\n * - 'today, 3pm to 5pm'\n * - 'today, 3pm to tomorrow, 5pm'\n * - 'today, 3pm to 5pm (CDT)' (if `includeTz` is true)\n * - '3pm today to 5pm tomorrow' (if `timeFirst` is true)\n * - 'today to tomorrow' (if `dateOnly` is true)\n *\n * This uses `formatDateFriendlyString()` to format the individual dates and times.\n *\n * @param start The start date and time.\n * @param end The end date and time.\n * @param timezone The time zone to use for formatting.\n * @param options Additional options for formatting the displayed date, taken from `formatDateFriendlyString()`.\n * @returns Human-readable string representing the datetime range.\n */\nexport function formatDateRangeFriendly(\n start: Date,\n end: Date,\n timezone: string,\n {\n baseDate = new Date(),\n includeTz = true,\n timeFirst = false,\n dateOnly = false,\n }: Parameters<typeof formatDateFriendly>[2] = {},\n): string {\n const {\n dateFormatted: startDateFormatted,\n timeFormatted: startTimeFormatted,\n timezoneFormatted,\n } = formatDateFriendlyParts(start, timezone, baseDate);\n const { dateFormatted: endDateFormatted, timeFormatted: endTimeFormatted } =\n formatDateFriendlyParts(end, timezone, baseDate);\n\n let result: string | undefined;\n if (dateOnly) {\n if (startDateFormatted === endDateFormatted) {\n result = startDateFormatted;\n } else {\n result = `${startDateFormatted} to ${endDateFormatted}`;\n }\n } else {\n if (startDateFormatted === endDateFormatted) {\n let timeRangeFormatted: string | undefined;\n if (startTimeFormatted === endTimeFormatted) {\n timeRangeFormatted = startTimeFormatted;\n } else {\n timeRangeFormatted = `${startTimeFormatted} to ${endTimeFormatted}`;\n }\n if (timeFirst) {\n result = `${timeRangeFormatted} ${startDateFormatted}`;\n } else {\n result = `${startDateFormatted}, ${timeRangeFormatted}`;\n }\n } else {\n if (timeFirst) {\n result = `${startTimeFormatted} ${startDateFormatted} to ${endTimeFormatted} ${endDateFormatted}`;\n } else {\n result = `${startDateFormatted}, ${startTimeFormatted} to ${endDateFormatted}, ${endTimeFormatted}`;\n }\n }\n }\n if (includeTz) {\n result = `${result} ${timezoneFormatted}`;\n }\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"date.js","sourceRoot":"","sources":["../src/date.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,KAAK,MAAM,iBAAiB,CAAC;AAIpC;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,IAAU,EACV,QAAgB,EAChB,EACE,SAAS,GAAG,IAAI,EAChB,MAAM,GAAG,KAAK,EACd,SAAS,GAAG,KAAK,MACiD,EAAE;IAEtE,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,sBAAsB,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;QACjD,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;KACxC,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAClJ,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,IAAI,KAAK,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;IACrE,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IACnE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAU,EAAE,QAAgB;IACxD,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;KACf,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,QAAgB;IAC1D,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;KAClB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACjH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE;QAC7C,QAAQ;QACR,YAAY,EAAE,OAAO;KACtB,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACvB,MAAM,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,CAAC;IACxD,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC;AAClC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAU,EACV,QAAgB,EAChB,EAAE,SAAS,GAAG,IAAI,KAA8B,EAAE;IAElD,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,aAAa,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtF,IAAI,SAAS,EAAE,CAAC;QACd,aAAa,GAAG,GAAG,aAAa,KAAK,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IACnE,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAU,EACV,UAAgB,EAChB,QAAc,EACd,QAAgB;IAEhB,MAAM,OAAO,GAA+B;QAC1C,QAAQ;QACR,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,SAAS;QAChB,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,SAAS,GAAG,KAAK,CACrB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAC7D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IACF,MAAM,UAAU,GAAG,KAAK,CACtB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,UAAU,CAAC,EACnE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IACF,MAAM,QAAQ,GAAG,KAAK,CACpB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,QAAQ,CAAC,EACjE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;IAEF,mCAAmC;IACnC,MAAM,OAAO,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAC1F,MAAM,QAAQ,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,KAAK,IAAI,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAC9F,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK,CAAC,KAAK,IAAI,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAEtF,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC;QAC/C,2DAA2D;QAC3D,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC7D,CAAC;IAED,4CAA4C;IAC5C,MAAM,KAAK,GAAG,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC1C,MAAM,IAAI,GAAG,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAEtC,uEAAuE;IACvE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,OAAO,GAA+B;YAC1C,QAAQ;YACR,KAAK,EAAE,OAAO;YACd,GAAG,EAAE,SAAS;YACd,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,SAAS;SAClB,CAAC;QACF,MAAM,SAAS,GAAG,KAAK,CACrB,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAC7D,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CACd,CAAC;QACF,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC9G,CAAC;IAED,6BAA6B;IAC7B,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;AACrI,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAS,uBAAuB,CAC9B,IAAU,EACV,QAAgB,EAChB,QAAc,EACd,eAA8B,QAAQ,EACtC,eAA8B,MAAM;IAEpC,gFAAgF;IAEhF,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACxF,MAAM,aAAa,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAEhF,MAAM,aAAa,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAE9C,MAAM,UAAU,GAAG,SAAS,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC;IAE/E,wCAAwC;IAExC,MAAM,OAAO,GAA+B;QAC1C,QAAQ,EAAE,QAAQ;QAClB,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,OAAO;QACd,GAAG,EAAE,SAAS;QACd,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,KAAK;QAChB,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACtB,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAElG,yBAAyB;IAEzB,IAAI,aAAa,GAAG,EAAE,CAAC;IACvB,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,aAAa,GAAG,OAAO,CAAC;IAC1B,CAAC;SAAM,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QAC5B,aAAa,GAAG,UAAU,CAAC;IAC7B,CAAC;SAAM,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;QAC7B,aAAa,GAAG,WAAW,CAAC;IAC9B,CAAC;SAAM,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,EAAE,CAAC;QACvC,gEAAgE;QAChE,aAAa,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IACzF,CAAC;SAAM,CAAC;QACN,aAAa,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAAC,KAAK,SAAS,KAAK,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IAC9G,CAAC;IAED,MAAM,cAAc,GAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACrE,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAEtD;;;;;;;;;;;;;;;;OAgBG;IAEH,6HAA6H;IAC7H,IAAI,QAAQ,GAAG,QAAQ,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,kEAAkE,CAAC,CAAC;IACtF,CAAC;IAED;;;;;;;;;OASG;IAEH,IAAI,aAAa,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC;IAErC,MAAM,iBAAiB,GACrB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC3C,CAAC,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC;QAC1D,CAAC,YAAY,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC;IAE9F,IAAI,iBAAiB,EAAE,CAAC;QACtB,aAAa,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,iBAAiB,GACrB,YAAY,KAAK,QAAQ,IAAI,CAAC,YAAY,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC;IAE1F,IAAI,iBAAiB,EAAE,CAAC;QACtB,aAAa,IAAI,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IAC5C,CAAC;IACD,qBAAqB;IACrB,aAAa,GAAG,GAAG,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;IAEzE,sBAAsB;IAEtB,MAAM,iBAAiB,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,KAAK,GAAG,CAAC;IAE1D,OAAO;QACL,aAAa;QACb,aAAa;QACb,iBAAiB;KAClB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAU,EACV,QAAgB,EAChB,EACE,QAAQ,GAAG,IAAI,IAAI,EAAE,EACrB,SAAS,GAAG,IAAI,EAChB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,QAAQ,GAAG,KAAK,EAChB,YAAY,GAAG,QAAQ,EACvB,YAAY,GAAG,MAAM,MASnB,EAAE;IAEN,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,GAAG,uBAAuB,CACjF,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,YAAY,CACb,CAAC;IAEF,IAAI,iBAAiB,GAAG,EAAE,CAAC;IAC3B,IAAI,QAAQ,EAAE,CAAC;QACb,iBAAiB,GAAG,aAAa,CAAC;IACpC,CAAC;SAAM,IAAI,QAAQ,EAAE,CAAC;QACpB,iBAAiB,GAAG,aAAa,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,IAAI,SAAS,EAAE,CAAC;YACd,iBAAiB,GAAG,GAAG,aAAa,IAAI,aAAa,EAAE,CAAC;QAC1D,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,GAAG,aAAa,KAAK,aAAa,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,iBAAiB,GAAG,GAAG,iBAAiB,IAAI,iBAAiB,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,iBAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAW,EACX,GAAS,EACT,QAAgB,EAChB,EACE,QAAQ,GAAG,IAAI,IAAI,EAAE,EACrB,SAAS,GAAG,IAAI,EAChB,SAAS,GAAG,KAAK,EACjB,QAAQ,GAAG,KAAK,EAChB,YAAY,GAAG,QAAQ,EACvB,YAAY,GAAG,MAAM,MACuB,EAAE;IAEhD,MAAM,EACJ,aAAa,EAAE,kBAAkB,EACjC,aAAa,EAAE,kBAAkB,EACjC,iBAAiB,GAClB,GAAG,uBAAuB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IACnF,MAAM,EAAE,aAAa,EAAE,gBAAgB,EAAE,aAAa,EAAE,gBAAgB,EAAE,GACxE,uBAAuB,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,CAAC,CAAC;IAE/E,IAAI,MAA0B,CAAC;IAC/B,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;YAC5C,MAAM,GAAG,kBAAkB,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,kBAAkB,OAAO,gBAAgB,EAAE,CAAC;QAC1D,CAAC;IACH,CAAC;SAAM,CAAC;QACN,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;YAC5C,IAAI,kBAAsC,CAAC;YAC3C,IAAI,kBAAkB,KAAK,gBAAgB,EAAE,CAAC;gBAC5C,kBAAkB,GAAG,kBAAkB,CAAC;YAC1C,CAAC;iBAAM,CAAC;gBACN,kBAAkB,GAAG,GAAG,kBAAkB,OAAO,gBAAgB,EAAE,CAAC;YACtE,CAAC;YACD,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,EAAE,CAAC;YACzD,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,kBAAkB,KAAK,kBAAkB,EAAE,CAAC;YAC1D,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,GAAG,GAAG,kBAAkB,IAAI,kBAAkB,OAAO,gBAAgB,IAAI,gBAAgB,EAAE,CAAC;YACpG,CAAC;iBAAM,CAAC;gBACN,MAAM,GAAG,GAAG,kBAAkB,KAAK,kBAAkB,OAAO,gBAAgB,KAAK,gBAAgB,EAAE,CAAC;YACtG,CAAC;QACH,CAAC;IACH,CAAC;IACD,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,MAAM,IAAI,iBAAiB,EAAE,CAAC;IAC5C,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { toTemporalInstant } from '@js-temporal/polyfill';\nimport keyBy from 'lodash/keyBy.js';\n\ntype TimePrecision = 'hour' | 'minute' | 'second';\n\n/**\n * Format a date to a human-readable string like '2020-03-27T12:34:56 (CDT)'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @param param2.includeTz Whether to include the time zone in the output (default true).\n * @param param2.longTz Whether to use the long time zone name (default false).\n * @returns Human-readable string representing the date.\n */\nexport function formatDate(\n date: Date,\n timeZone: string,\n {\n includeTz = true,\n longTz = false,\n includeMs = false,\n }: { includeTz?: boolean; longTz?: boolean; includeMs?: boolean } = {},\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n fractionalSecondDigits: includeMs ? 3 : undefined,\n timeZoneName: longTz ? 'long' : 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n let dateFormatted = `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n if (includeMs) {\n dateFormatted = `${dateFormatted}.${parts.fractionalSecond.value}`;\n }\n if (includeTz) {\n dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;\n }\n return dateFormatted;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMD(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value}`;\n}\n\n/**\n * Format a date to a human-readable string like '2020-03-27 14:27'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateYMDHM(date: Date, timeZone: string): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n return `${parts.year.value}-${parts.month.value}-${parts.day.value} ${parts.hour.value}:${parts.minute.value}`;\n}\n\n/**\n * Format a time zone to a human-readable string like 'CDT'.\n *\n * @param timeZone The time zone to format.\n * @returns Human-readable string representing the time zone.\n */\nexport function formatTz(timeZone: string): string {\n const date = new Date();\n const parts = new Intl.DateTimeFormat('en-US', {\n timeZone,\n timeZoneName: 'short',\n }).formatToParts(date);\n const tz = parts.find((p) => p.type === 'timeZoneName');\n return tz ? tz.value : timeZone;\n}\n\n/**\n * Format a date to a human-readable string like '14:27:00 (CDT)'.\n *\n * @param date The date to format.\n * @param timeZone The time zone to use for formatting.\n * @param param2.includeTz Whether to include the time zone in the output (default true).\n * @returns Human-readable string representing the date.\n */\nexport function formatDateHMS(\n date: Date,\n timeZone: string,\n { includeTz = true }: { includeTz?: boolean } = {},\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n timeZoneName: 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n let dateFormatted = `${parts.hour.value}:${parts.minute.value}:${parts.second.value}`;\n if (includeTz) {\n dateFormatted = `${dateFormatted} (${parts.timeZoneName.value})`;\n }\n return dateFormatted;\n}\n\n/**\n * Format a date to a human-readable string like '18:23' or 'May 2, 07:12',\n * where the precision is determined by the range.\n *\n * @param date The date to format.\n * @param rangeStart The start of the range.\n * @param rangeEnd The end of the range.\n * @param timeZone The time zone to use for formatting.\n * @returns Human-readable string representing the date.\n */\nexport function formatDateWithinRange(\n date: Date,\n rangeStart: Date,\n rangeEnd: Date,\n timeZone: string,\n): string {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n hourCycle: 'h23',\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n timeZoneName: 'short',\n };\n const dateParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(date),\n (x) => x.type,\n );\n const startParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(rangeStart),\n (x) => x.type,\n );\n const endParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(rangeEnd),\n (x) => x.type,\n );\n\n // format the date (not time) parts\n const dateYMD = `${dateParts.year.value}-${dateParts.month.value}-${dateParts.day.value}`;\n const startYMD = `${startParts.year.value}-${startParts.month.value}-${startParts.day.value}`;\n const endYMD = `${endParts.year.value}-${endParts.month.value}-${endParts.day.value}`;\n\n if (dateYMD === startYMD && dateYMD === endYMD) {\n // only show the time if the date is the same for all three\n return `${dateParts.hour.value}:${dateParts.minute.value}`;\n }\n\n // format the year, but not the month or day\n const dateY = `${dateParts.year.value}`;\n const startY = `${startParts.year.value}`;\n const endY = `${endParts.year.value}`;\n\n // if the year is the same for all three, show the month, day, and time\n if (dateY === startY && dateY === endY) {\n const options: Intl.DateTimeFormatOptions = {\n timeZone,\n month: 'short',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n };\n const dateParts = keyBy(\n new Intl.DateTimeFormat('en-US', options).formatToParts(date),\n (x) => x.type,\n );\n return `${dateParts.month.value} ${dateParts.day.value}, ${dateParts.hour.value}:${dateParts.minute.value}`;\n }\n\n // fall back to the full date\n return `${dateParts.year.value}-${dateParts.month.value}-${dateParts.day.value} ${dateParts.hour.value}:${dateParts.minute.value}`;\n}\n\n/**\n * Format a Date to date and time strings in the given time zone. The date is\n * formatted like\n * - 'today'\n * - 'Mon, Mar 20' (if within 180 days of the base date)\n * - 'Wed, Jan 1, 2020'\n *\n * The time format leaves off zero minutes and seconds, and uses 12-hour time,\n * giving strings like\n * - '3pm'\n * - '3:34pm'\n * - '3:34:17pm'\n *\n * maxPrecision must be an equal or smaller unit than minPrecision.\n *\n * @param date The date to format.\n * @param timezone The time zone to use for formatting.\n * @param baseDate The base date to use for comparison.\n * @param maxPrecision Only show units as large or larger than the max precision.\n * @param minPrecision Always show that unit and larger, potentially showing smaller units.\n *\n */\nfunction formatDateFriendlyParts(\n date: Date,\n timezone: string,\n baseDate: Date,\n maxPrecision: TimePrecision = 'second',\n minPrecision: TimePrecision = 'hour',\n): { dateFormatted: string; timeFormatted: string; timezoneFormatted: string } {\n // compute the number of days from the base date (0 = today, 1 = tomorrow, etc.)\n\n const baseZonedDateTime = toTemporalInstant.call(baseDate).toZonedDateTimeISO(timezone);\n const zonedDateTime = toTemporalInstant.call(date).toZonedDateTimeISO(timezone);\n\n const basePlainDate = baseZonedDateTime.toPlainDate();\n const plainDate = zonedDateTime.toPlainDate();\n\n const daysOffset = plainDate.since(basePlainDate, { largestUnit: 'day' }).days;\n\n // format the parts of the date and time\n\n const options: Intl.DateTimeFormatOptions = {\n timeZone: timezone,\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n weekday: 'short',\n hourCycle: 'h12',\n hour: 'numeric',\n minute: '2-digit',\n second: '2-digit',\n timeZoneName: 'short',\n };\n const parts = keyBy(new Intl.DateTimeFormat('en-US', options).formatToParts(date), (x) => x.type);\n\n // format the date string\n\n let dateFormatted = '';\n if (daysOffset === 0) {\n dateFormatted = 'today';\n } else if (daysOffset === 1) {\n dateFormatted = 'tomorrow';\n } else if (daysOffset === -1) {\n dateFormatted = 'yesterday';\n } else if (Math.abs(daysOffset) <= 180) {\n // non-breaking-space (\\u00a0) is used between the month and day\n dateFormatted = `${parts.weekday.value}, ${parts.month.value}\\u00a0${parts.day.value}`;\n } else {\n dateFormatted = `${parts.weekday.value}, ${parts.month.value}\\u00a0${parts.day.value}, ${parts.year.value}`;\n }\n\n const precisionOrder: TimePrecision[] = ['second', 'minute', 'hour'];\n const maxIndex = precisionOrder.indexOf(maxPrecision);\n const minIndex = precisionOrder.indexOf(minPrecision);\n\n /**\n * The maximum precision must be a unit smaller than or equal to the minimum precision, otherwise the rules will contradict each other.\n *\n * If max is a larger unit than min, e.g. max = hour, min = minute, then by \"min\"\n * we must display minute and smaller but by \"max\" we can display hour and larger, which is a contradiction.\n *\n * If min is a larger unit than max, e.g. max = minute, min = hour, then by \"min\" we must display\n * hour and smaller and by \"max\" we can display minutes and larger. These do not contradict each other.\n *\n * V min/max > | h | m | s\n * h | X | X | X\n * m | I | X | X\n * s | I | I | X\n *\n * X - valid configuration\n * I - invalid configuration\n */\n\n // A higher index corresponds to a larger unit, so if maxIndex is larger than minIndex, then the rules contradict each other.\n if (maxIndex > minIndex) {\n throw new Error('maxPrecision must be an equal or smaller unit than minPrecision.');\n }\n\n /** Examples:\n * min=h, max=h: 0:00:00AM -> 0AM, 0:00:01AM -> 0AM, 0:01:01AM -> 0AM\n * min=h, max=m: 0:00:00AM -> 0AM, 0:00:01AM -> 0AM, 0:01:01AM -> 0:01AM\n * min=h, max=s: 0:00:00AM -> 0AM, 0:00:01AM -> 0:00:01AM, 0:01:01AM -> 0:01:01AM\n *\n * min=m, max=m: 0:00:00AM -> 0:00AM, 0:00:01AM -> 0:00AM, 0:01:01AM -> 0:00AM\n * min=m, max=s: 0:00:00AM -> 0:00AM, 0:00:01AM -> 0:00AM, 0:01:01AM -> 0:01:01AM\n *\n * min=s, max=s: 0:00:00AM -> 0:00:00AM, 0:00:01AM -> 0:00:01AM, 0:01:01AM -> 0:01:01AM\n */\n\n let timeFormatted = parts.hour.value;\n\n const shouldShowMinutes =\n ['minute', 'second'].includes(minPrecision) ||\n (maxPrecision === 'minute' && parts.minute.value !== '00') ||\n (maxPrecision === 'second' && (parts.minute.value !== '00' || parts.second.value !== '00'));\n\n if (shouldShowMinutes) {\n timeFormatted += `:${parts.minute.value}`;\n }\n\n const shouldShowSeconds =\n minPrecision === 'second' || (maxPrecision === 'second' && parts.second.value !== '00');\n\n if (shouldShowSeconds) {\n timeFormatted += `:${parts.second.value}`;\n }\n // add the am/pm part\n timeFormatted = `${timeFormatted}${parts.dayPeriod.value.toLowerCase()}`;\n\n // format the timezone\n\n const timezoneFormatted = `(${parts.timeZoneName.value})`;\n\n return {\n dateFormatted,\n timeFormatted,\n timezoneFormatted,\n };\n}\n\n/**\n * Format a date to a string like:\n * - 'today, 3pm'\n * - 'tomorrow, 10:30am'\n * - 'yesterday, 11:45pm'\n * - 'Mon, Mar 20, 8:15am' (if within 180 days of the base date)\n * - 'Wed, Jan 1, 2020, 12pm'\n * - `today, 3pm (CDT)` (if `includeTz` is true)\n * - `3pm today` (if `timeFirst` is true)\n * - 'today' (if `dateOnly` is true)\n *\n * If using this within a sentence like `... at ${formatDateFriendlyString()}`,\n * use `timeFirst: true` to improve readability.\n *\n * @param date The date to format.\n * @param timezone The time zone to use for formatting.\n * @param param.baseDate The base date to use for comparison (default is the current date).\n * @param param.includeTz Whether to include the time zone in the output (default true).\n * @param param.timeFirst If true, the time is shown before the date (default false).\n * @param param.dateOnly If true, only the date is shown (default false).\n * @param param.timeOnly If true, only the time is shown (default false).\n * @param param.maxPrecision The maximum precision to show for time (default 'minute').\n * @param param.minPrecision The minimum precision to always show for time (default 'hour').\n * @returns Human-readable string representing the date and time.\n */\nexport function formatDateFriendly(\n date: Date,\n timezone: string,\n {\n baseDate = new Date(),\n includeTz = true,\n timeFirst = false,\n dateOnly = false,\n timeOnly = false,\n maxPrecision = 'second',\n minPrecision = 'hour',\n }: {\n baseDate?: Date;\n includeTz?: boolean;\n timeFirst?: boolean;\n dateOnly?: boolean;\n timeOnly?: boolean;\n maxPrecision?: TimePrecision;\n minPrecision?: TimePrecision;\n } = {},\n): string {\n const { dateFormatted, timeFormatted, timezoneFormatted } = formatDateFriendlyParts(\n date,\n timezone,\n baseDate,\n maxPrecision,\n minPrecision,\n );\n\n let dateTimeFormatted = '';\n if (dateOnly) {\n dateTimeFormatted = dateFormatted;\n } else if (timeOnly) {\n dateTimeFormatted = timeFormatted;\n } else {\n if (timeFirst) {\n dateTimeFormatted = `${timeFormatted} ${dateFormatted}`;\n } else {\n dateTimeFormatted = `${dateFormatted}, ${timeFormatted}`;\n }\n }\n if (includeTz) {\n dateTimeFormatted = `${dateTimeFormatted} ${timezoneFormatted}`;\n }\n return dateTimeFormatted;\n}\n\n/**\n * Format a datetime range to a string like:\n * - 'today, 10am'\n * - 'today, 3pm to 5pm'\n * - 'today, 3pm to tomorrow, 5pm'\n * - 'today, 3pm to 5pm (CDT)' (if `includeTz` is true)\n * - '3pm today to 5pm tomorrow' (if `timeFirst` is true)\n * - 'today to tomorrow' (if `dateOnly` is true)\n *\n * This uses `formatDateFriendlyString()` to format the individual dates and times.\n *\n * @param start The start date and time.\n * @param end The end date and time.\n * @param timezone The time zone to use for formatting.\n * @param options Additional options for formatting the displayed date, taken from `formatDateFriendlyString()`.\n * @returns Human-readable string representing the datetime range.\n */\nexport function formatDateRangeFriendly(\n start: Date,\n end: Date,\n timezone: string,\n {\n baseDate = new Date(),\n includeTz = true,\n timeFirst = false,\n dateOnly = false,\n maxPrecision = 'second',\n minPrecision = 'hour',\n }: Parameters<typeof formatDateFriendly>[2] = {},\n): string {\n const {\n dateFormatted: startDateFormatted,\n timeFormatted: startTimeFormatted,\n timezoneFormatted,\n } = formatDateFriendlyParts(start, timezone, baseDate, maxPrecision, minPrecision);\n const { dateFormatted: endDateFormatted, timeFormatted: endTimeFormatted } =\n formatDateFriendlyParts(end, timezone, baseDate, maxPrecision, minPrecision);\n\n let result: string | undefined;\n if (dateOnly) {\n if (startDateFormatted === endDateFormatted) {\n result = startDateFormatted;\n } else {\n result = `${startDateFormatted} to ${endDateFormatted}`;\n }\n } else {\n if (startDateFormatted === endDateFormatted) {\n let timeRangeFormatted: string | undefined;\n if (startTimeFormatted === endTimeFormatted) {\n timeRangeFormatted = startTimeFormatted;\n } else {\n timeRangeFormatted = `${startTimeFormatted} to ${endTimeFormatted}`;\n }\n if (timeFirst) {\n result = `${timeRangeFormatted} ${startDateFormatted}`;\n } else {\n result = `${startDateFormatted}, ${timeRangeFormatted}`;\n }\n } else {\n if (timeFirst) {\n result = `${startTimeFormatted} ${startDateFormatted} to ${endTimeFormatted} ${endDateFormatted}`;\n } else {\n result = `${startDateFormatted}, ${startTimeFormatted} to ${endDateFormatted}, ${endTimeFormatted}`;\n }\n }\n }\n if (includeTz) {\n result = `${result} ${timezoneFormatted}`;\n }\n return result;\n}\n"]}
|