Offsets, Zones, and the Golden Rules
You now know an instant is not a clock reading. The next trap is subtler, and it catches people who think they've got time figured out: treating an offset as if it were a time zone. They look similar. They are not the same thing, and the difference is exactly the thing that breaks twice a year.
An offset is a number. A zone is a rulebook.
An offset is how far a local clock currently sits from UTC, written like +02:00 or -05:00. It's a single number describing one moment. "Right now, Berlin is two hours ahead of UTC" — that's an offset.
A time zone is a named region with a complete set of rules about what its offset is, and — crucially — when that offset changes. Europe/Berlin is a zone. Its rules say: most of the year the offset is +01:00, but from late March to late October it's +02:00, and here are the exact instants it switches.
Offset: +02:00 a number. true for ONE moment. tells you nothing about tomorrow.
Zone: Europe/Berlin a rulebook. knows it's +01:00 in winter, +02:00 in summer,
and the precise dates it flips between them — past and future.
What just happened: the offset +02:00 is a snapshot; Europe/Berlin is the whole film. If you store only +02:00, you've thrown away the rules — so you can't correctly compute what a Berlin clock will read three months from now, because you don't know whether daylight saving will have flipped by then. The offset can't tell you. The zone can.
This is why "store the offset" is a trap. The offset is right today and wrong after the next daylight-saving switch. The zone stays right forever, because it carries the rules.
The IANA database: where the rules actually live
You might wonder: who decides that Berlin flips on the last Sunday of March? Governments do — and they change their minds, sometimes with only weeks of notice. Countries add daylight saving, drop it, shift their offset, redraw zone boundaries. This is messy, political, and constantly moving.
So nobody sane hand-codes these rules. There is one authoritative, community-maintained dataset that every serious system uses: the IANA Time Zone Database (also called tz or zoneinfo). It's the source of names like America/New_York, Asia/Kolkata, and Europe/Berlin, and for each one it records the full history and the current rules of that region's offset changes. When a government announces a change, the database is updated, and your operating system, language runtime, and libraries pull in the new version.
IANA zone names look like Area/Location
America/New_York
Europe/London
Asia/Tokyo
Australia/Sydney
Each entry encodes: current offset(s) + the rules & dates for every change,
historical and future, as governments have defined them.
What just happened: the database turns "what time is it in Sydney" from a guess into a lookup. You name the zone; the library reads IANA's rules; you get the right offset for the specific instant you asked about — including the awkward instants around a daylight-saving switch. You never write these rules yourself, because they're not yours to know.
Use IANA names (
Europe/Berlin), never abbreviations likeEST,CST, orIST. Abbreviations are ambiguous —ISTmeans India, Ireland, and Israel time depending on who's talking — and they don't carry daylight-saving rules. The IANA name is the only label that's both unique and complete.
The golden rules
Everything above collapses into four habits. Follow them and the whole hairy domain becomes boring, which is exactly what you want from time handling.
1. Store and compute in UTC (or Unix timestamps). Inside your system — your database, your business logic, your comparisons — work only with instants. They're unambiguous, they sort correctly, and arithmetic on them is honest. Never store a local wall-clock time as your source of truth.
2. Convert only at the edges. A human types a local time on the way in → convert it to UTC immediately. You show a time on the way out → convert UTC to the viewer's local zone at the last possible moment. The conversions live at the boundary; the core never sees a local time.
user input "3pm Berlin" display "shows as 9am New York"
| ^
v convert in | convert out
+---------------------------------------------------------+
| CORE: everything is UTC / Unix timestamps |
| store, compare, sort, do math — all on instants |
+---------------------------------------------------------+
What just happened: this is the shape of every well-behaved time system. Local times exist only at the rim, as input and output. The middle is pure instants, so none of the daylight-saving chaos from Phase 3 can leak into your logic.
3. Never hand-roll zone math. Do not add or subtract hours yourself to "convert time zones." The moment you write hour + 2, you've assumed an offset that's wrong half the year, and you've ignored every IANA rule. This is the single most common way time code breaks.
4. Use a real, IANA-backed library. Every mainstream language has one — and the modern, correct one is usually not the old built-in date type your language shipped with originally. Reach for the library that knows zones: ZonedDateTime in Java, the zoneinfo module in Python, Temporal (or a library like Luxon/date-fns-tz) in JavaScript, chrono-tz in Rust, time.LoadLocation in Go. Let it do the lookups. Your job is to name the zone correctly and stay out of the way.
# A human picks a wall-clock time in Berlin — convert to an instant at the edge.
=
# Store / compute as the unambiguous instant (UTC):
=
# Display the same instant to a viewer in New York — convert at the other edge:
=
What just happened: one instant, named once in Berlin's zone, then converted in and out. The library read IANA's rules to figure the correct offsets — you never wrote a single + hours. That's all four rules in eight lines: convert at the edge, keep an instant in the middle, lean on the zone database, hand-roll nothing.
For builders
Audit your storage. If a date column anywhere holds a local time with no zone, that's a latent bug waiting for a user in another region or the next daylight-saving switch. The fix is mechanical: store the instant (UTC / timestamp), and store the user's IANA zone separately if you need to reconstruct their local view. Two clean fields beat one ambiguous one every time.
[
{
"q": "What's the difference between the offset +02:00 and the zone Europe/Berlin?",
"choices": [
"Nothing — they're two ways of writing the same thing",
"The offset is a single number true for one moment; the zone is a rulebook that also knows when the offset changes",
"The offset is more precise than the zone",
"Europe/Berlin is an abbreviation for +02:00"
],
"answer": 1,
"explain": "An offset is a snapshot of distance-from-UTC. A zone carries the full rules, including the dates the offset flips — so only the zone survives a daylight-saving switch."
},
{
"q": "What is the IANA Time Zone Database used for?",
"choices": [
"Storing every user's preferred date format",
"Converting Unix timestamps to integers",
"Recording the authoritative rules and history of each region's offset changes, under names like America/New_York",
"Synchronizing computer clocks over the network"
],
"answer": 2,
"explain": "IANA (tz/zoneinfo) is the shared, maintained source of truth for zone rules. Libraries read it so nobody hand-codes when Berlin flips for daylight saving."
},
{
"q": "Which practice follows the golden rules?",
"choices": [
"Store local wall-clock times and add or subtract hours when you need another zone",
"Store and compute in UTC, convert to local only at input and output, and let an IANA-backed library do the zone math",
"Store the current offset (like +05:00) alongside each timestamp as the source of truth",
"Use abbreviations like EST and IST so the zone is human-readable"
],
"answer": 1,
"explain": "UTC in the core, conversions at the edges, no hand-rolled hour math, and a real zone-aware library — that's the whole safe recipe."
}
]
← Phase 1 | Overview | Phase 3: The 2am That Happens Twice →
Check your understanding 3 questions
1. What's the difference between the offset +02:00 and the zone Europe/Berlin?
2. What is the IANA Time Zone Database used for?
3. Which practice follows the golden rules?