45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
const FALLBACK_TIME_ZONE = "UTC";
|
|
|
|
export function isValidTimeZone(value: string): boolean {
|
|
if (!value.trim()) return false;
|
|
try {
|
|
new Intl.DateTimeFormat("en-US", { timeZone: value }).format(0);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getLocalTimeZone(): string {
|
|
const resolved = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
return resolved && isValidTimeZone(resolved) ? resolved : FALLBACK_TIME_ZONE;
|
|
}
|
|
|
|
export function formatZonedDateTime(
|
|
value: Date | string | number,
|
|
timeZone = getLocalTimeZone(),
|
|
options: Intl.DateTimeFormatOptions = {},
|
|
): string {
|
|
const date = value instanceof Date ? value : new Date(value);
|
|
if (Number.isNaN(date.getTime())) return "Invalid date";
|
|
|
|
return new Intl.DateTimeFormat("en-US", {
|
|
dateStyle: "medium",
|
|
timeStyle: "short",
|
|
...options,
|
|
timeZone: isValidTimeZone(timeZone) ? timeZone : FALLBACK_TIME_ZONE,
|
|
}).format(date);
|
|
}
|
|
|
|
export function getDefaultScheduledSendAt(now = new Date()): Date {
|
|
const result = new Date(now);
|
|
result.setMinutes(0, 0, 0);
|
|
result.setHours(result.getHours() + 1);
|
|
return result;
|
|
}
|
|
|
|
export function toLocalDateTimeInputValue(value: Date): string {
|
|
const pad = (part: number) => String(part).padStart(2, "0");
|
|
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}T${pad(value.getHours())}:${pad(value.getMinutes())}`;
|
|
}
|