If your column is TIMESTAMPTZ , but your application sends a naive timestamp, PostgreSQL will assume the timestamp is in your session's time zone. If your server is in UTC and your user is in Sydney – .
If you have ever built an app that serves users across multiple time zones, you’ve likely woken up to a 3:00 AM page about "incorrect order dates" or "meetings showing up at the wrong hour." postgres timestamp vs timestamptz
To preserve the user's original time zone (e.g., for compliance or display), you need a : If your column is TIMESTAMPTZ , but your
If you change your session time zone to 'Asia/Tokyo' (UTC+9) and read the table: Your future self (and your global users) will thank you
If you care when something happened, use TIMESTAMPTZ . Your future self (and your global users) will thank you. Have a horror story about timestamps gone wrong? Share it in the comments below!
-- Assume my session time zone is 'America/New_York' SET TIME ZONE 'America/New_York'; -- Create a test table CREATE TABLE time_test ( ts_native TIMESTAMP, -- without tz ts_tz TIMESTAMPTZ -- with tz );
Always use in your application code. Quick Decision Flowchart Is this a single, absolute moment in time? │ ├── YES (e.g., created_at, updated_at, event start time for global users) │ → Use TIMESTAMPTZ │ └── NO (e.g., "Every day at 9 AM" recurring alarm) → Use TIMESTAMP + store time zone separately in another column Pro Tip: TIMESTAMPTZ Does NOT Store the Time Zone This is the #1 misunderstanding. TIMESTAMPTZ does not save 'America/Chicago' or '+05:30' . It converts your input to UTC, stores UTC, and discards the original offset.