Why Time Zones Are Complicated
Time zones seem simple on the surface: the Earth is divided into 24 slices, each offset from UTC by a whole number of hours. Reality is messier. There are over 600 distinct timezone identifiers in active use. Some offsets are half-hours or quarter-hours. Countries change their rules. And daylight saving time means the same timezone can have different offsets depending on the time of year.
UTC: The Global Reference Point
Coordinated Universal Time (UTC) is the primary time standard the world uses as a reference. It is not tied to any geographic location and does not observe daylight saving time. Every other timezone is defined as an offset from UTC — for example, UTC+5:30 (India Standard Time) or UTC-5:00 (US Eastern in winter).
When storing timestamps in databases or transmitting them across systems, always use UTC. Convert to local time only at the point of display. This single practice eliminates an entire class of timezone-related bugs.
UTC Offsets vs. IANA Timezone Names
An offset like `UTC+9` tells you the current difference from UTC, but not which timezone you are in. Japan and South Korea both use UTC+9, but Japan does not observe daylight saving time while South Korea discontinued it in 1988. If you only store an offset, you cannot correctly handle future times around DST transitions.
The IANA Time Zone Database provides named identifiers like `America/New_York`, `Europe/London`, `Asia/Tokyo`. These names encode both the current offset and the full history of all offset changes, including DST rules. Any software dealing with future times — calendaring, scheduling, recurring reminders — should always use IANA names rather than raw offsets.
IANA names follow `Region/City` format. The city is the largest in that timezone zone, not necessarily the capital.
Daylight Saving Time: The Perennial Source of Bugs
DST shifts clocks forward in spring and back in autumn. About 70 countries observe DST, but start and end dates vary — and rules have changed multiple times over the past century.
In the US, DST begins on the second Sunday of March (clocks spring forward at 2:00 AM to 3:00 AM) and ends on the first Sunday of November (clocks fall back at 2:00 AM to 1:00 AM). This creates a "lost hour" in spring and a "repeated hour" in autumn.
That repeated hour is where bugs hide. A nightly job scheduled at 1:30 AM local time runs twice the night clocks fall back. UTC-based scheduling avoids this entirely.
Common Conversion Mistakes
**Mistake 1: Assuming all offsets are whole hours.** India uses UTC+5:30. Nepal uses UTC+5:45. Always use a proper library, not manual arithmetic.
**Mistake 2: Treating UTC+0 as UTC.** The UK uses `Europe/London`, which is UTC+0 in winter but UTC+1 in summer. Hardcoding UTC+0 is wrong half the year.
**Mistake 3: Storing local times without timezone context.** "2026-03-08 02:30:00" is ambiguous — that moment may not even exist in some timezones (it falls in the spring-forward gap in US Eastern time).
**Mistake 4: Parsing timezone abbreviations.** CST means Central Standard Time in North America, China Standard Time elsewhere. IANA names are unambiguous.
Working With Time Zones in Practice
**For display:** convert UTC timestamps to the user's local timezone using the browser's `Intl.DateTimeFormat` API or a library like `date-fns-tz` or `Luxon`. Never hardcode timezone conversions.
**For scheduling:** store the IANA timezone name alongside any future-facing time. "Every Monday at 9:00 AM America/Chicago" handles DST transitions automatically.
**For APIs:** ISO 8601 with UTC offset is the standard: `2026-04-16T14:30:00Z` (Z means UTC) or `2026-04-16T09:30:00-05:00`. Prefer the Z suffix.
**For Unix timestamps:** a Unix timestamp is seconds since 1970-01-01T00:00:00Z — always UTC, always unambiguous. Convert to human-readable local time only at the UI layer.