timezones
<tosijs-timezone-picker> carries no static timezone dataset. The list is built at
import time from the
Intl
global, so it costs almost nothing to ship and always agrees with the runtime it is
running in — including the current DST state.
This is the whole dataset, live, in your browser right now — no download involved:
const local = Intl.DateTimeFormat().resolvedOptions().timeZone
const zones = Intl.supportedValuesOf('timeZone')
preview.textContent =
`Intl offers this browser ${zones.length} timezones, and says you are in ${local}.`
Timezone
interface Timezone {
name: string // the IANA name, e.g. 'America/Los_Angeles'
shortName?: string // 'America/Los_Angeles' has none; 'America/Indiana/Knox' → 'America/Knox'
abbr: string // the runtime's short name, e.g. 'PDT'
offset: number // hours from GMT, e.g. -7 (fractional offsets are decimals: 5.5, -3.5)
}
offset is the offset right now, not the zone's standard offset — half the world's
zones move by an hour twice a year and the map moves with them.
Exports
timezones: Timezone[]— every zoneIntl.supportedValuesOf('timeZone')reports.localTimezone: Timezone— the runtime's own zone, resolved throughtimezoneAliasesand falling back toUTCif the runtime reports a zone it doesn't otherwise list.zoneFromName(name)— look up by IANA name,shortName, or deprecated alias.zoneId(zone)— the human-readable id shown in the picker's text field, e.g.'America/Los Angeles GMT-7'.zoneFromId(id)— the inverse ofzoneId.
Renamed zones, and why zoneFromName asks twice
IANA renames zones — Europe/Kiev → Europe/Kyiv, Asia/Calcutta → Asia/Kolkata,
Asia/Rangoon → Asia/Yangon — and engines disagree about which name they admit to.
The two Intl APIs disagree with each other, too:
Intl.supportedValuesOf('timeZone')enumerates one name per zone, and which half of a renamed pair you get is per-engine. V8 tends to list the new name, JavaScriptCore the old one. Neither tells you the other exists.Intl.DateTimeFormataccepts both halves, plus legacy links the enumeration never mentions (US/Pacific,Asia/Chongqing,Etc/GMT+5), and throwsRangeErroronly for a name that genuinely isn't a zone.
So zoneFromName tries the enumerated list first (exact name, then shortName, then
timezoneAliases), and finally asks Intl.DateTimeFormat whether the runtime will format
it. The practical effect: a zone name your app stored years ago keeps resolving after IANA
retires it, on whichever engine your user shows up with, without this package shipping a
rename table that has to be maintained.
timezoneAliases still earns its place — it is what lets a map region labelled with one
spelling light up when the runtime uses the other. Names outside the enumeration resolve
fine but have no polygon, so they are reachable by typing rather than by clicking.
Zones with no region on the map
The map's geometry predates a number of tzdb splits (America/Ciudad_Juarez,
America/Punta_Arenas, America/Coyhaique…), and Antarctica has never had polygons. Those
zones are selectable through the text field but can't be clicked. See regions.