I want to save in Postgres TIMESTAMP WITH TIME ZONE
column
2012-08-24 14:00:00+03:00
After a SELECT
I am getting:
2012-08-24 11:00:00+00:00
I know that my DB is on UTC zone, but is there a way to save it and not lose original timezone info that I sent?
2
Answers
No date/time type stores time zone because it’s a separate piece of information. Do not use plain
timestamp
if your source data comes with timezone offsets because it’ll be trimmed off – thetimestamptz
is just as light, just as flexible, and it doesn’t truncate the offset. If you wish to retain the source offset/timezone, you need to save it to a separate column – timestamp is meant to store a when not a where – the latter is only used to clarify the former.If offset or other valid time zone info is present in the value literal/constant, it’s used to shift the timestamp to UTC for internal storage. When the db reads it back to you when you
select
, it’s shifted once again according to yourtimezone
setting: demo at db<>fiddleThe offset you see by default when you select a
timestamptz
is your current timezone: it basically means this timestamp, as observed in a timezone with this offset. Note that unless you add the minutes:00
, it’s trimmed off as insignificant both in default output and into_char()
formatting function. If you really want to get the output you specified, for a reason only known to you, by all means you can – simply set the setting accordingly:tl;dr
Postgres adjusts all
TIMESTAMP WITH TIME ZONE
inputs to UTC, an offset of zero. Retrieved values remain in UTC, an offset of zero.If you need the original offset, record that info in another column.
Postgres adjusts to UTC (offset of zero)
As you have seen, and as documented, for a column of type
TIMESTAMP WITH TIME ZONE
, Postgres uses the input’s offset-from-UTC to adjust to an offset of zero hours-minutes-seconds.Your offset indicates a time of 14:00 with an offset of 3 hours ahead of UTC. So Postgres adjusts the time to 11:00 with an offset of zero. Same moment, same point on the timeline, different perspective.
Beware of tooling with auto-adjust anti-feature
Postgres retrieves the stored value with its offset of zero.
Unfortunately, many tools choose to dynamically apply some default time zone onto the retrieved value. While well-intentioned, this anti-feature confuses the picture, creates an illusion that the moment was stored with a particular time zone or offset. But, no, in Postgres values in a
TIMESTAMP WITH TIME ZONE
are always stored in UTC (offset of zero), and always retrieved in UTC (offset of zero).Behavior varies across database engines
The SQL standard barely addresses date-time issues. So much of date-time handling behavior in various databases is implementation-specific.
Some other database engines do the same as Postgres, auto-adjusting to an offset of zero. But some database engines may not. Always study the doc.
Store offset in another column
If knowing the original offset is important to you, you’ll need to save that fact as a value in another column. I would suggest a column of a textual type, storing offset values in standard ISO 8601 format.