As you already figured out yourself, the time zone is not saved at all with Postgres date / time types, not even with timestamptz
. Its role is just an input modifier or output decorator, respectively. Only the value (the point in time) is saved. Ample details in this related answer:
Therefore, if you want to preserve that part of the input string, you have to extract it from the string and save it yourself. I would use a table like:
CREATE TABLE tstz
...
, ts timestamp -- without time zone
, tz text
)
tz
, being text
, can hold a numeric offset as well as a time zone abbreviation, or a time zone name.
The difficulty is to extract the time zone part according to all the various rules the parser follows and in a way that won't break easily. Instead of cooking up your own procedure, make the parser do the work. Consider this demo:
WITH ts_literals (tstz) AS (
VALUES ('2013-11-28 23:09:11.761166+03'::text)
, ('2013-11-28 23:09:11.761166 CET')
, ('2013-11-28 23:09:11.761166 America/New_York')
)
SELECT tstz
, tstz::timestamp AS ts
, right(tstz, -1 * length(tstz::timestamp::text)) AS tz
FROM ts_literals;
db<>fiddle here
Old sqlfiddle
Works with or without a T
between date and time. The key logic is here:
right(tstz, -1 * length(tstz::timestamp::text)) AS tz
Take what's left of a timestamp string after trimming the length of what the parser identified as date / time component. This relies on the input being, as you stated:
validated ISO 8601 strings