Understanding Timezones and UTC Offsets
A practical guide to timezones — understand UTC, IANA timezone names, UTC offsets, Daylight Saving Time, and how to reliably work with times across zones in code.
UTC — the universal reference point
Coordinated Universal Time (UTC) is the world's primary time standard. It has no daylight saving offset and never changes. Every timezone on Earth is defined as UTC plus or minus some offset. When you need to store, compare, or transmit a moment in time, UTC is the correct representation — convert to a local timezone only when displaying to users.
UTC offsets
A UTC offset expresses how many hours (and sometimes minutes) a timezone is ahead of or behind UTC. Most offsets are whole hours, but some regions use :30 or :45. The offset can change during the year due to Daylight Saving Time.
UTC+0:00 — London (winter), Reykjavik
UTC+1:00 — Paris, Berlin, Lagos (winter in Europe)
UTC+2:00 — Cairo, Johannesburg
UTC+3:00 — Moscow, Riyadh, Nairobi
UTC+5:30 — Mumbai, Kolkata, Chennai (IST — no DST)
UTC+8:00 — Singapore, Beijing, Perth
UTC+9:00 — Tokyo, Seoul
UTC-5:00 — New York (winter, EST)
UTC-8:00 — Los Angeles (winter, PST)
UTC+5:45 — Kathmandu (Nepal — rare :45 offset)IANA timezone names vs abbreviations
Timezone abbreviations like EST, PST, and IST are ambiguous — IST means Indian Standard Time, Irish Standard Time, and Israel Standard Time. Always use IANA timezone names (the tz database) for unambiguous, DST-aware identification. They follow the format Region/City.
Ambiguous abbreviation → IANA name
──────────────────────────────────────
IST → Asia/Kolkata (India)
IST → Europe/Dublin (Ireland in summer)
IST → Asia/Jerusalem
EST → America/New_York (Eastern, no DST rules included)
America/New_York → handles EST and EDT automatically
Other common IANA names:
Europe/London Europe/Paris Europe/Berlin
Asia/Tokyo Asia/Singapore Asia/Dubai
Australia/Sydney America/Chicago America/Los_Angeles
Pacific/Auckland America/Sao_PauloDaylight Saving Time (DST)
Many regions advance their clocks by one hour in summer (DST) and revert in winter, effectively changing their UTC offset. Not all regions observe DST — Japan, India, China, and most of Africa do not. DST transitions happen on different dates in different countries, making offset arithmetic unreliable without a proper timezone library.
# New York offsets — UTC-5 (EST) in winter, UTC-4 (EDT) in summer
# 2024 transition dates:
# Spring forward: March 10, 2024 at 2:00 AM → 3:00 AM
# Fall back: November 3, 2024 at 2:00 AM → 1:00 AM
# London offset — UTC+0 (GMT) in winter, UTC+1 (BST) in summer
# 2024 transitions:
# Spring forward: March 31, 2024
# Fall back: October 27, 2024
# This means New York and London are 5h apart in winter but 4h in spring/autumnWorking with timezones in JavaScript
The Intl.DateTimeFormat API and Date methods handle timezone display. For arithmetic across DST boundaries, use the Temporal API (modern) or a library like date-fns-tz or Luxon.
const now = new Date(); // always UTC internally
// Display in a specific timezone
now.toLocaleString("en-US", { timeZone: "America/New_York" });
now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" });
// Full format with timezone name
new Intl.DateTimeFormat("en-US", {
timeZone: "America/New_York",
dateStyle: "full",
timeStyle: "long",
}).format(now);
// "Monday, November 14, 2024 at 5:13:20 PM EST"
// Convert a specific datetime from one zone to another
const formatter = new Intl.DateTimeFormat("sv", {
timeZone: "Asia/Tokyo",
year: "numeric", month: "2-digit", day: "2-digit",
hour: "2-digit", minute: "2-digit",
});
formatter.format(now); // "2024-11-15 07:13"Working with timezones in Python
Python's zoneinfo module (Python 3.9+) provides IANA timezone support. Always use timezone-aware datetimes — naive datetimes have no timezone context and cause subtle bugs.
from datetime import datetime
from zoneinfo import ZoneInfo
utc_now = datetime.now(ZoneInfo("UTC"))
# Convert to another timezone
kolkata = utc_now.astimezone(ZoneInfo("Asia/Kolkata"))
new_york = utc_now.astimezone(ZoneInfo("America/New_York"))
print(kolkata.strftime("%Y-%m-%d %H:%M %Z")) # 2024-11-15 06:43 IST
print(new_york.strftime("%Y-%m-%d %H:%M %Z")) # 2024-11-14 20:13 EST
# Get UTC offset including DST
print(new_york.utcoffset()) # -1 day, 19:00:00 (= UTC-5)Should I store timestamps in UTC or local time?
Always store in UTC. Convert to the user's local timezone at display time. Storing local times causes ambiguity during DST transitions (one hour repeats) and makes comparisons and sorting unreliable.
Why do some timezone offsets have :30 or :45 minutes?
When countries adopted standard time in the 19th and 20th centuries, some chose offsets aligned to their local solar time rather than a whole hour. India (UTC+5:30), Sri Lanka (UTC+5:30), and Nepal (UTC+5:45) are examples.
What is the difference between GMT and UTC?
For everyday purposes they are the same — both represent zero offset. Technically, GMT is a timezone (and can observe BST in summer in the UK), while UTC is an international time standard maintained with atomic clocks. In programming, use UTC.
How to Convert an Epoch (Unix) Timestamp
A practical guide to Unix epoch timestamps — what they are, how to convert them to human-readable dates, and how to work with them in JavaScript, Python, and the command line.
Read guide →Working with Dates Across Time Zones in JavaScript
A practical guide to JavaScript dates — the Date object, UTC vs local time, formatting, parsing, and how to avoid the most common time zone bugs.
Read guide →