Lesson 07·Unit 3 · The Intl toolbox·Time zones & calendar edge cases·Lv 201·~8 min
Time zones, DST, and Lord Howe Island
There are 38 distinct UTC offsets in use today, including half-hour and 45-minute zones. Samoa skipped December 30, 2011. Lord Howe Island shifts the clock 30 minutes for DST. Storing user timestamps as 'UTC plus a number' is how features break twice a year.
By the end
- ·Explain what an IANA zone name knows that a UTC offset never will.
- ·Decide what to store for something that already happened, and what to store for a meeting next spring.
- ·Convert a meeting across zones and spot the weeks where two countries change clocks on different days.
The problem
Time zones aren't a math problem. They're a political problem maintained by the IANA tzdata team and updated 5–10 times a year. Russia abolishes DST, then reinstates parts of it. Turkey switches permanent +03. Antarctica's stations rotate offsets seasonally. Code that stores "UTC + 5 hours" instead of "Asia/Karachi" breaks the day the rule changes. Schedules, calendar invites, billing cycles all start firing at the wrong time.
How it works
An offset is a moment; a zone is a history
UTC+2 tells you what a clock reads right now. Europe/Berlin tells you what clocks there have read for over a century and what they will do next spring. A zone name is a key into the IANA time zone database, a curated archive of political decisions. Countries adopt DST, abolish it, and nudge offsets. Once a whole country hopped the date line, so December 30, 2011 never happened in Samoa.
This is why the storage rule has two halves. For things that happened, store the instant (UTC). For things scheduled by humans ("March 3rd, 9 AM, my time"), store wall time plus the zone name. The promise is about the local clock, and governments change the mapping between clocks and instants with months of notice. tzdata ships multiple releases most years to keep up. An offset you froze at booking time cannot.
Never let arithmetic assume whole hours: India runs +5:30, Nepal +5:45, and Lord Howe Island's DST shifts the clock thirty minutes, not sixty. Each is a real market with real users whose appointments your rounding would move.
See it yourself
Try these, in order
Each step triggers a specific failure you should recognize on sight.
- 1Keep Australia/Lord_Howe selected and read “the flip, frame by frame”. 01:59 at +10:30 becomes 02:30 at +11:00: a thirty-minute DST jump. “DST is always one hour” is a falsehood with a named counterexample.
- 2Pick “Pacific/Apia · skipped a calendar day”. 23:59 on Dec 29, 2011 rolls directly into Dec 31. The frame-by-frame shows a whole calendar date that never existed locally.
- 3Find Asia/Kathmandu and Asia/Kolkata in the live world clock. +05:45 and +05:30: the minutes column differs from UTC's. A UI that renders only “GMT+5” is off by 45 minutes for Nepal.
- 4Pick “Africa/Casablanca · pauses for Ramadan”. Morocco observes year-round DST except during Ramadan: a rule tied to a lunar calendar, so the civil-time change moves every year. Only tzdata keeps up.
- 5In “Convert a meeting”, keep the defaults (09:00 on 2026-10-28, “Source zone” Europe/London) and compare the two target rows. New York reads 05:00 at GMT-4 and carries the badge “DST boundary within a week of this meeting”. US clocks fall back on Nov 1, 2026, so the same wall time one week later is a different instant. Tokyo reads 18:00 at GMT+9 with no badge: Japan has no DST. Same meeting, different amounts of trust.
- 6Change “Source zone” to America/New_York and set “Meeting time” to 02:30 on 2026-03-08. A warning appears: that wall time does not exist in New York. Clocks jump from 02:00 to 03:00 at the spring DST boundary. Every scheduler needs a policy for times its users can type but their clocks will never show.
Standard offset is UTC+10:30. DST adds 30 minutes, not 60. The only inhabited place on Earth with a half-hour DST flip.
The flip, frame by frame
01:59 just before DST
4 Oct 2026, 01:59
UTC+10:30
02:30 just after DST
4 Oct 2026, 02:30
UTC+11:00
At 02:00 the clock jumped straight to 02:30, a 30-minute shift.
Convert a meeting
Type a wall-clock time, say whose wall it is, and read the same instant in up to three other zones. Each row is Intl.DateTimeFormat with timeZone + timeZoneName, no arithmetic of your own.
| Zone | Meeting reads | Offset | |
|---|---|---|---|
| Europe/London (source) | Wed, 28 Oct 2026, 09:00 GMT | UTC+00:00 | |
| America/New_York | Wed, 28 Oct 2026, 05:00 GMT-4 | UTC-04:00 | DST boundary within a week of this meeting |
| Asia/Tokyo | Wed, 28 Oct 2026, 18:00 GMT+9 | UTC+09:00 |
The warning compares each target zone's UTC offset at the meeting with its offset 7 days later. When they differ, a recurring “same wall time next week” event lands at a different instant, the classic cross-zone standup bug.
Live world clock · —
The same instant, formatted in every featured zone. Refresh rate: 1 Hz. The offset column uses timeZoneName: 'longOffset'.
| IANA zone | Local time | Offset |
|---|---|---|
| UTC | — | — |
| Pacific/Honolulu | — | — |
| America/Los_Angeles | — | — |
| America/New_York | — | — |
| America/Argentina/Buenos_Aires | — | — |
| Europe/London | — | — |
| Europe/Berlin | — | — |
| Africa/Cairo | — | — |
| Asia/Kolkata | — | — |
| Asia/Kathmandu | — | — |
| Asia/Tokyo | — | — |
| Australia/Lord_Howe | — | — |
| Pacific/Auckland | — | — |
| Pacific/Apia | — | — |
Things you almost certainly believe that are wrong
- Time zones have whole-hour offsets. False. India is +05:30, Nepal is +05:45, Lord Howe is +10:30 standard and +11:00 in DST.
- DST always shifts the clock by an hour. False: see Lord Howe (30 min).
- Every day has 24 hours. False. The day DST starts in spring has 23. The day DST ends in autumn has 25. Samoa's Dec 30, 2011 had zero hours.
- UTC and GMT are the same thing. Close enough for most apps. But different bodies define them, and they can drift by up to 0.9 seconds before a leap-second correction.
- A country has one timezone. China spans five geographically but enforces one (UTC+8). The US has six. France has twelve (counting overseas territories, the most of any country).
Practical engineering rules
- Store instants in UTC ISO-8601 with milliseconds.
- Format on the client with
Intl.DateTimeFormat(locale, { timeZone: userTz }). - Take the user's tz from
Intl.DateTimeFormat().resolvedOptions().timeZone. Do not ask the user to pick from a dropdown unless they are a sysadmin. - Round-trip your test fixtures through a DST flip (March + October). Bugs hide in the spring-forward boundary.
- Update the IANA tzdata at least quarterly. Governments change tz rules on short notice. Your container image will not get the patch by accident.
If you remember one thing
Store UTC instants plus an IANA zone name for anything human-scheduled. Offsets are political, they change, and some of them end in :30 and :45.
What to do about it
- Always store IANA time-zone IDs (
Europe/Berlin,America/Sao_Paulo), not offsets. Offsets describe a moment; IDs describe a region. - For display, use
new Intl.DateTimeFormat(locale, { timeZone: id, timeZoneName: "long" }). The browser handles DST transitions, abbreviations, and historical offset changes. - For recurring events ("every Tuesday at 10am"), store the rule in the user's local time-zone ID and resolve to a UTC instant per occurrence. Storing as a UTC instant breaks across DST changes.
- Subscribe to the IANA tzdata announcement list and bump the tzdata package in your runtime within a week of each release.
Use this with
Stakeholders
Moments
- ·Designing scheduling, calendar, or recurring billing features
- ·DST changeover (twice a year)
- ·Launching into a region with a non-standard offset (India, Iran, Nepal, Australia)
Field note
On 29 December 2011, Samoa ended the day and went straight to 31 December. The country hopped the International Date Line to align its week with Australia and New Zealand, and 30 December 2011 never happened there. Any system that stored “next appointment: Dec 30, local” had an appointment on a date that did not exist. tzdata carries this. Naive offset math does not.
Quick check
3 questions · pass at 2+
Question 1/3
A 09:00 London standup has a New York attendee. Europe ends DST on Oct 25, 2026, and the US on Nov 1. When does the Oct 28 standup reach New York?
Question 2/3
What happened to 30 December 2011 in Samoa?
Question 3/3
You are saving a user's future appointment (“March 3, 9:00 AM, their time”). What should you store?