SQL types and the type system
Dates, times and time zones
The idea in 30 seconds
timestamptz stores one exact instant and shows it in whatever time zone your session uses. timestamp without time zone stores only the clock reading and throws away any offset you give it. For anything that happened at a moment in time (orders, payments, logins), use timestamptz.
Helps to know first: SQL data modification
On this page
Two kinds of timestamp
PostgreSQL has two timestamp types, and the names are misleading:
| Type | What it stores | On output |
|---|---|---|
timestamptz (timestamp with time zone) | One exact instant, kept internally in UTC | Converted to the session’s time zone |
timestamp (without time zone) | A date and a clock reading, nothing more | Exactly as stored |
Despite its name, timestamptz does not remember the time zone you gave it. It uses the zone to work out the exact instant, stores that instant, and forgets the zone.
See the difference
Store the moment Asha placed her first order, 10:15 in Pune, in both types:
CREATE TEMP TABLE events (label text, with_tz timestamptz, without_tz timestamp);
INSERT INTO events VALUES
('order placed in Pune', '2025-03-02 10:15+05:30', '2025-03-02 10:15+05:30');
Now read it back from sessions in three different time zones:
| Session time zone | with_tz | without_tz |
|---|---|---|
UTC | 2025-03-02 04:45:00+00 | 2025-03-02 10:15:00 |
Asia/Kolkata | 2025-03-02 10:15:00+05:30 | 2025-03-02 10:15:00 |
America/New_York | 2025-03-01 23:45:00-05 | 2025-03-02 10:15:00 |
with_tz is the same instant every time, shown on three different clocks: in New York it was still the evening before. without_tz says “10:15” everywhere, and nothing in it tells you where those 10:15 were. The +05:30 in the input was silently thrown away.
PredictComparing two orders
A customer in New York and a customer in Pune each place an order at “10:15 on 2 March” on their own clocks. The times are stored in a timestamp (without time zone) column. Which order came first?
You cannot tell from the data. Both rows say 2025-03-02 10:15:00. In reality the Pune order came first: 10:15 in Pune is 04:45 UTC, while 10:15 in New York is 15:15 UTC. With timestamptz, the two values would differ by ten and a half hours and sort correctly.
Showing local time
To display an instant as a particular place’s local time, use AT TIME ZONE:
SELECT ordered_at, ordered_at AT TIME ZONE 'Asia/Kolkata' AS pune_local_time
FROM orders WHERE id = 101;
ordered_at | pune_local_time
------------------------+---------------------
2025-03-02 04:45:00+00 | 2025-03-02 10:15:00
The result is a plain clock reading for display, not an instant to store.
When plain timestamp and date are right
datefor things that are a whole day wherever you are: a birthday, a joining date, an invoice date.customers.joined_onis adate.timestampwithout time zone for a wall-clock time that should not move with the viewer: “the shop opens at 09:00”, in whichever city the shop is.
Everything that happened at a moment, use timestamptz.
Check yourself
What does
timestamptzactually store?Show answer
One exact instant, held internally as UTC. The time zone given on input is used to compute that instant and is then discarded; output is converted to the session’s time zone.
You insert
'2025-03-02 10:15+05:30'into atimestampcolumn. What is stored?Show answer
2025-03-02 10:15:00. For timestamp without time zone, PostgreSQL silently ignores the offset, so the information about which 10:15 is lost.Which type for an order’s placed-at time, a user’s birthday, and a store’s daily opening time?
Show answer
timestamptzfor the order (a moment),datefor the birthday (a whole day), andtimeortimestampwithout time zone for the opening time (a wall-clock reading).
Finished reading?
Saved in this browser only.
Sources
Where each claim on this page comes from.
- 1.PostgreSQL documentation: 8.5 Date/Time TypesPrimary· §8.5.1.3 Time Stamps
For timestamp with time zone, input is converted to UTC and stored as UTC, the original zone is not kept, and output is converted to the session's TimeZone; for timestamp without time zone, any zone in the input is silently ignored.
- 2.PostgreSQL documentation: 9.9 Date/Time Functions and OperatorsPrimary· §9.9.4 AT TIME ZONE and AT LOCAL
AT TIME ZONE converts a timestamp with time zone to the local time in a given zone, as a timestamp without time zone.
Go further
What to read next, and why it is worth the time.
- 1.PostgreSQL documentation: 8.5 Date/Time TypesPrimary· §8.5.1.3 Time Stamps, §8.5.3 Time Zones
The precise rules for both timestamp types and how PostgreSQL names time zones.
Applies to PostgreSQL 18. Draft: not yet fact-checked end to end.