POSIX-style TZ strings like IST-2 cause a hard RangeError crash in formatMessages because Intl.DateTimeFormat only accepts IANA identifiers. - Add isValidTimezone/resolveTimezone helpers to src/timezone.ts - Make formatLocalTime fall back to UTC on invalid timezone - Validate TZ candidates in config.ts before accepting - Add timezone setup step to detect and prompt when autodetection fails - Use node:22-slim in Dockerfile (node:24-slim Trixie package renames) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
38 lines
947 B
TypeScript
38 lines
947 B
TypeScript
/**
|
|
* Check whether a timezone string is a valid IANA identifier
|
|
* that Intl.DateTimeFormat can use.
|
|
*/
|
|
export function isValidTimezone(tz: string): boolean {
|
|
try {
|
|
Intl.DateTimeFormat(undefined, { timeZone: tz });
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return the given timezone if valid IANA, otherwise fall back to UTC.
|
|
*/
|
|
export function resolveTimezone(tz: string): string {
|
|
return isValidTimezone(tz) ? tz : 'UTC';
|
|
}
|
|
|
|
/**
|
|
* Convert a UTC ISO timestamp to a localized display string.
|
|
* Uses the Intl API (no external dependencies).
|
|
* Falls back to UTC if the timezone is invalid.
|
|
*/
|
|
export function formatLocalTime(utcIso: string, timezone: string): string {
|
|
const date = new Date(utcIso);
|
|
return date.toLocaleString('en-US', {
|
|
timeZone: resolveTimezone(timezone),
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: '2-digit',
|
|
hour12: true,
|
|
});
|
|
}
|