1.0.37
This commit is contained in:
101 files changed
+5097
-642
No files matched your search
@@ -82,3 +82,75 @@ export function formatTimePartWith(
|
||||
: `${hour24}:${minutes}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Offset of a timezone from UTC (in ms) at a given instant.
|
||||
* Positive for zones ahead of UTC (e.g. UTC+2 -> 7_200_000).
|
||||
*/
|
||||
function tzOffsetMs(timeZone: string, at: Date): number {
|
||||
const dtf = new Intl.DateTimeFormat('en-US', {
|
||||
timeZone,
|
||||
hourCycle: 'h23',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
});
|
||||
const parts = dtf.formatToParts(at);
|
||||
const get = (type: Intl.DateTimeFormatPartTypes) =>
|
||||
parseInt(parts.find((p) => p.type === type)?.value ?? '0', 10);
|
||||
const asUtc = Date.UTC(get('year'), get('month') - 1, get('day'), get('hour'), get('minute'), get('second'));
|
||||
// Drop sub-second precision of `at` - formatToParts only has seconds
|
||||
return asUtc - Math.floor(at.getTime() / 1000) * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Current calendar date in a timezone as 'YYYY-MM-DD'.
|
||||
* Falsy timeZone means the browser's local timezone.
|
||||
*/
|
||||
export function currentDateInTimezone(timeZone?: string): string {
|
||||
const now = new Date();
|
||||
if (!timeZone) {
|
||||
const y = now.getFullYear();
|
||||
const m = String(now.getMonth() + 1).padStart(2, '0');
|
||||
const d = String(now.getDate()).padStart(2, '0');
|
||||
return `${y}-${m}-${d}`;
|
||||
}
|
||||
const parts = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}).formatToParts(now);
|
||||
const get = (type: Intl.DateTimeFormatPartTypes) => parts.find((p) => p.type === type)?.value ?? '';
|
||||
return `${get('year')}-${get('month')}-${get('day')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* UTC instant (ISO string) of a day boundary in a timezone: midnight for the
|
||||
* start of the day, 23:59:59.999 for the end. Used to turn date-only filter
|
||||
* values ('YYYY-MM-DD', meaning a day in the user's configured timezone) into
|
||||
* timestamps comparable against UTC-stored event times (#1269).
|
||||
* Falsy timeZone means the browser's local timezone.
|
||||
*/
|
||||
export function dayBoundaryToUtcISO(dateStr: string, timeZone: string | undefined, endOfDay: boolean): string {
|
||||
const [y, m, d] = dateStr.split('-').map(Number);
|
||||
const h = endOfDay ? 23 : 0;
|
||||
const min = endOfDay ? 59 : 0;
|
||||
const s = endOfDay ? 59 : 0;
|
||||
const ms = endOfDay ? 999 : 0;
|
||||
|
||||
if (!timeZone) {
|
||||
return new Date(y, m - 1, d, h, min, s, ms).toISOString();
|
||||
}
|
||||
|
||||
const wallClockUtc = Date.UTC(y, m - 1, d, h, min, s, ms);
|
||||
// Two passes so DST transitions near the boundary converge on the right offset
|
||||
let ts = wallClockUtc;
|
||||
for (let i = 0; i < 2; i++) {
|
||||
ts = wallClockUtc - tzOffsetMs(timeZone, new Date(ts));
|
||||
}
|
||||
return new Date(ts).toISOString();
|
||||
}
|
||||
Reference in new issue
Block a user