Skip to content

How to: Time Zone

Date, time, and timezone 101.

Key Concepts

Timestamp

A timestamp is a single, globally unambiguous point in time. Think of it as a continuous count of seconds since a fixed reference point (the epoch, typically January 1, 1970, 00:00:00).

Timezone

A timezone communicates the relationship between a timestamp and local time. It encapsulates complex rules, including current and historical Daylight Saving Time adjustments.

Always use identifiers from the IANA Time Zone Database (e.g., America/New_York, Europe/London) to store, interpret, and calculate time. Also known as the tz database or zoneinfo, it is maintained by the Internet Assigned Numbers Authority and is available across modern operating systems and programming languages.

"GMT-0400", "EST", and "-04:00" are not timezones. They are merely offsets from UTC. They do not contain DST rules and lack a standardized database. There is no reason to store these offsets as your source of truth.

The terms "timezone" and "offset" are often misused interchangeably. In everyday language we might say "I’m in the EST timezone" instead of "I’m in the America/Toronto timezone." This leads to confusion and design errors. As software engineers, correct terminology is critical for robust systems.

Offsets are still useful for debugging. End users should never see raw time data, but formats like 2025-07-25T00:57:01+04:00 strike a balance between developer-friendliness and machine-friendliness, compared to raw epoch timestamps like 1753404882.

Date, Time, & Datetime

Definition of Date, Time, and Datetime

Date

A date is a combination of year, month, and day in a calendar system (usually the Gregorian calendar).

Each calendar system is well-defined. Dates follow rules such as the number of days in each month, leap years, and skipped days.

Time

Time is also a well-defined system. Practically, we all use the same one: hours, minutes, seconds, and optionally fractions of a second. There are 60 seconds in a minute, 60 minutes in an hour, and 24 hours in a day.

Datetime

A datetime is a combination of date and time. It represents a picture of the clock, not a point in time.

Datetime values tied to a timezone can be ill-defined – ambiguous or invalid. During DST transitions, certain times may never occur, or they may occur twice. Parsing such values without extra context will leads to errors.

General Rules to Handle Datetime

For most apps, minimal explicit timezone handling is needed beyond consistently storing points in time.

Always store a point in time, not a picture of a clock. When persisting data, always store the epoch timestamp. This preserves the exact moment, regardless of how it is accessed.

  • Good: 1753404882 (Unix epoch, always UTC)
  • Good: Fri, 25 Jul 2025 00:56:29 GMT (RFC 2822 format)
  • Good: 2025-07-25T00:57:01.636Z (ISO 8601 format)
  • Good: 2025-07-25T00:57:01.636+04:00 (ISO 8601 with offset)
  • Bad: 2025-07-25T00:57:01.636 (ambiguous "picture of a clock")
  • Bad: 2025-07-24 20:59:33.095283 (ambiguous "picture of a clock")

Communicate points in time using interoperable formats. Always use a well-known standard.

Translate to local time at the user interface level. Display times in the end user's local timezone. Only perform such translation at the UI level, on the user's device where the system timezone is available.

When Timezone Needs to Be Stored

Physical Events

For events tied to a physical location (concert, flight, restaurant reservation, doctor’s appointment), store the IANA timezone alongside the event.

Think of the timezone as event metadata, not part of the timestamp itself.

In the user interface, show additional information if the event timezone differs from the device timezone.

User's Timezone Unavailable

We can usually get the user’s timezone on mobile or web apps. But for emails, push notifications, or other server-initiated events, we don't know the timezone.

If a user's timezone isn't expected to change: allow a user setting to store preferences.

If a user's timezone is expected to change: (e.g., travel apps) always include the timezone with the time, or display relative times (e.g., "flight is departing tomorrow at 3 PM in 24 hours").

Timezone-Sensitive Logic

Phone alarms: An alarm set for 7 AM should ring at 7 AM local time, even across DST shifts.

Recurring tasks: Clarify whether "1 AM" means local time or a fixed UTC time. DST transitions will cause some intervals to be 23 or 25 hours.

Scheduling: Meetings like "every day 9 AM Pacific Time" must adjust correctly across timezones and DST changes.

General approach to logic hotspots:

  1. Avoid entirely: If business requirements allow, schedule tasks using UTC.
  2. Avoid DST transition hours: These usually occur between 11 PM–3 AM.
  3. Design solutions explicitly: Decide how the system should behave in DST transition cases (e.g., should a 1:30 AM alarm ring twice?).
  4. Test extensively: Simulate DST changes, run tests in multiple timezones, and manually test on devices.

API Integrations

Due to inconsistent vocabulary and varying regional rules (many places don’t observe DST at all), timezone handling in integrations cannot be assumed reliable.

  1. Double-check documentation: Understand API expectations, especially around timezones.
  2. Test extensively: Verify behavior across DST transitions and the international date line.
  3. Monitor continuously: External systems may change timezone handling without notice.

Date and Time Formats

When exchanging or displaying date and time information, standardized formats are crucial:

  • Epoch: A number representing seconds or milliseconds since a reference point (e.g., Unix epoch: January 1, 1970, 00:00:00 UTC).
  • ISO 8601: Widely adopted for dates and times (e.g., 2025-07-19T20:49:18Z for UTC, or 2025-07-19T16:49:18-04:00 with offset).
  • RFC 3339: A profile of ISO 8601, common in internet protocols. ISO 8601 vs RFC 3339
  • Email/HTTP Header Format: Example: Fri, 19 Jul 2025 20:49:18 GMT. Used in email headers (RFC 2822) and HTTP headers (RFC 9110).

Programming Languages

With these definitions in place, let's now look at how some languages handle them.

Python

Understand the difference between aware vs. naive datetimes. Always use aware datetime objects (which include an offset).

Avoid datetime.utcnow() and similar methods. They return naive datetimes that aren’t tied to an offset, effectively just "pictures of a clock." They are deprecated as of Python 3.12.

Examples:

  • datetime.utcnow()
  • datetime.today()
  • datetime.now(timezone.utc)

Parsing epoch timestamps:

  • datetime.utcfromtimestamp(epoch)
  • datetime.fromtimestamp(epoch)
  • datetime.fromtimestamp(epoch, timezone.utc)

from datetime import * assumed above

PostgreSQL

Don’t use timestamp, use timestamptz (timestamp with time zone).

  • timestamp: a picture of a clock
  • timestamptz: an absolute point in time

Despite its name, timestamptz doesn’t store the timezone itself. See PostgreSQL’s official “Don’t Do This”.

JavaScript

Native JavaScript only provides the Date object.

Developers often use libraries like Moment.js, Day.js, or date-fns for more sophisticated datetime and timezone handling.

The upcoming Temporal API is designed to fix these shortcomings. It introduces distinct objects for points in time (Instant), dates without time (PlainDate), and dates with time but no timezone (PlainDateTime), along with explicit timezone objects.

Date of Birth: The Special Case

Never store a date of birth with a time or timezone. A birth date is a calendar day. Store it as a date without a time component. If a pure date type isn’t available, store it as a string. To calculate age, always compare year, month, and day components; do not try to derive from total days lived.

Other Adjacent Specifications

Excel

Excel stores dates as numbers, representing the number of days since January 1, 1900.

<time> HTML Element

The <time> HTML element provides semantic meaning for dates and times, aiding accessibility and machine readability.

html
<time datetime="2025-07-19T20:49:18Z">
  July 19, 2025 at 8:49:18 PM
</time>

EXIF for Photos

Many cameras don’t store timezone information. Photo timestamps are often just year–month–day–hour–minute–second tuples, leading to ambiguity across DST transitions or travel. Good photo management software allows batch adjustments.

Newer EXIF standards (e.g., 2.31 from 2016) introduced fields like OffsetTime to store UTC offsets. However, EXIF still represents timestamps as tuples, not as epoch numbers.

Created on 2025-07-24

Last updated on 2025-09-11