Concepts & human language

Instant vs civil time

The single most important distinction — a point on the timeline vs a reading on a calendar/clock.

There are two fundamentally different things people call “a time”, and mixing them up is the root of most date bugs.

An instant is an absolute point on the universal timeline — the same moment everywhere on Earth. “2026-06-05T14:00:00Z” names an instant. So does a Unix timestamp. Two observers in different time zones agree on when it happened; they only disagree on what their wall clocks read.

A civil time (also “local time” or “wall-clock time”) is a reading on a human calendar and clock: “June 5th, 3:00 PM”. By itself it does not name a point on the timeline — “3 PM” happened at different absolute instants in Tokyo and in New York. A civil time only becomes an instant when you attach a time zone (or offset).

Different languages have their own name for this zone-less value: Java’s LocalDate / LocalDateTime, JavaScript’s Temporal.PlainDate, Python’s “naive” datetime. They all mean the same thing — a calendar/clock reading with no zone attached. This guide says civil time rather than “local” to keep it distinct from a time that has already been resolved into a specific zone, which is what “local time” usually implies.

Why it matters

Storing a civil time and treating it like an instant (or vice versa) silently corrupts data the moment two time zones are involved.

Pitfall: Storing “2026-06-05 15:00” with no zone, then later assuming it’s UTC. If it was actually local, every downstream calculation is off by the offset — and the error changes across DST boundaries.

A rule of thumb

  • Recording when something happened → store an instant (UTC).
  • Recording a time on a human calendar (a 9 AM meeting, a store’s opening hours) → store a civil time + the zone it’s interpreted in, not a UTC instant. The instant changes when DST rules change; the civil intent does not.
Go deeper: why "future meeting in UTC" is a bug

If you convert a future civil time to a UTC instant now and store only that instant, a later change to that zone’s DST rules (governments change them) will make your stored instant point to the wrong wall-clock time. Store the civil time + zone id and resolve to an instant at the last responsible moment.

See also Time zones vs offsets and Store vs display.


← Back to all topics