fix(ui): canonicalize timezone dropdown to drop deprecated aliases

Resolve each IANA name via Intl.DateTimeFormat().resolvedOptions() so
aliases like Asia/Saigon collapse into their canonical form
(Asia/Ho_Chi_Minh). Prevents cron/heartbeat pickers from saving a
deprecated alias that diverges from the Go-side canonical name.

Closes #760
This commit is contained in:
viettranx committed 2026-04-18 15:09:46 +07:00
1 parent 001d9e23e3
commit c06d15be5f
1 file changed
+17 -2
+17 -2
View File
@@ -40,19 +40,34 @@ const FALLBACK_TIMEZONES: string[] = [
"Pacific/Auckland",
];
/** Resolve to canonical IANA name (drops deprecated aliases like Asia/Saigon → Asia/Ho_Chi_Minh). */
function canonicalizeTimezone(tz: string): string | null {
try {
return new Intl.DateTimeFormat("en-US", { timeZone: tz }).resolvedOptions().timeZone;
} catch {
return null;
}
}
/** All IANA timezones with dynamic UTC offsets, sorted by offset then name. */
export function getAllIanaTimezones(): TzOption[] {
if (_cachedTimezones) return _cachedTimezones;
let tzNames: string[];
try {
tzNames = (Intl as any).supportedValuesOf("timeZone") as string[];
} catch {
tzNames = FALLBACK_TIMEZONES;
}
// Chrome may omit "UTC" from the list
if (!tzNames.includes("UTC")) tzNames = ["UTC", ...tzNames];
const entries = tzNames.map((tz: string) => {
// Canonicalize + dedupe so deprecated aliases (e.g. Asia/Saigon) collapse into their canonical form.
const canonical = new Set<string>();
for (const tz of tzNames) {
const c = canonicalizeTimezone(tz);
if (c) canonical.add(c);
}
const entries = Array.from(canonical).map((tz: string) => {
const offset = formatUtcOffset(tz);
return { value: tz, label: `${tz} (${offset})`, _offset: parseOffsetMinutes(offset) };
});