PostgreSQL
timestamptz stores an instant; timestamp stores civil wall time with no zone.
PostgreSQL offers two timestamp types whose similar names mask a critical difference. timestamp (without time zone) stores a set of date-and-time fields exactly as given — year, month, day, hour, minute, second — with no zone information attached. It is a civil wall-clock reading. timestamptz (timestamp with time zone) stores an instant: whatever value you write in is converted to UTC internally, and the original offset or zone name is discarded. The name “with time zone” describes the input behaviour, not what gets retained.
On output, timestamptz is rendered in the current session’s TimeZone setting — which initdb derives from the server’s operating-system zone at cluster creation, so it is frequently not UTC unless you set it explicitly. Two sessions with different TimeZone settings will display the same stored value differently — but they are reading the same instant. This is the correct model for recording when something happened.
Use timestamptz for event timestamps, audit fields, and anything that represents a point in time. Reserve plain timestamp only when you genuinely mean a clock reading with no zone context (e.g. a recurring schedule template). PostgreSQL also provides date, time, and interval types for durations and partial values, and supports full IANA zone arithmetic through AT TIME ZONE and now().
Choosing the right type
When you store an instant as timestamp instead of timestamptz, the database never alerts you — it simply saves the numbers. The mistake only surfaces when a query runs in a session with a different TimeZone setting, or when you move data between systems that assume UTC.
Pitfall: Using timestamp (no time zone) to record event times. Because no zone is stored, there is no safe way to convert the values to UTC after the fact unless you can guarantee every writer used the same zone — and that guarantee is fragile across deployments, migrations, and daylight saving transitions.
Go deeper: what "with time zone" actually means in Postgres
The PostgreSQL documentation is explicit: timestamptz does not store a time zone. It stores a UTC value. The phrase “with time zone” signals that the type is time-zone aware in the sense that it participates in offset-aware input parsing and session-timezone-aware output rendering. A value like '2026-06-05 10:00:00-05' and '2026-06-05 15:00:00Z' are identical once stored.
This differs from some other systems (notably RFC 3339 strings or Java’s OffsetDateTime) that preserve the original offset. If you need to retain what offset the user originally supplied — for display fidelity or audit purposes — you must store it separately as a text or numeric column alongside the timestamptz column.
The session parameter TimeZone (set via SET TimeZone = 'America/New_York' or postgresql.conf) controls output rendering but never changes the stored value. Always confirm your application’s connection pool uses the TimeZone you expect, especially after server upgrades.
See also Instant vs civil time and Store vs display.