In fact, PG knows it all - to_char(x, 'TZ') differentiates CST from
CDT correctly, and at time zone EST5EDT respects DST as well.
When dealing with a timestamp Postgres knows:
- The setting of the GUC
timezone
.
- The data type.
- The value, which is the same count of seconds since '1970-1-1 0:0 UTC' for
timestamp
and timestamptz
. (Or, to be precise: UT1.)
- Details about other time zones in your date/time configuration files
When interpreting input, Postgres uses information about the provided time zone.
When rendering a timestamp value, Postgres uses the current timezone
setting, but time zone offset, abbreviation or name are only used to compute the correct value on input. They are not saved. It is impossible to extract that information later. More details in this related answer:
Your "correct" example is almost correct. TZ
of to_char()
returns 'CDT' for timestamps that fall in the daylight saving periods of Central Time and 'CST' else. Eastern Time (EST
/EDT
) switches daylight saving hours at the same local time - I quote Wikipedia:
The time is adjusted at 2:00 AM local time.
The two time zones are out of sync during two hours per year. Of course, this can never affect a timestamp at 15:00
or 16:00
, only around 02:00
.
A fully correct solution - much like what @Daniel already posted, slightly simplified:
BEGIN;
SET LOCAL timezone to 'EST5EDT';
SELECT to_char('2012-05-29 15:00 CST6CDT'::timestamptz
, 'YYYY-MM-DD HH24:MI:SS TZ')
RESET timezone; -- only if more commands follow in this transactions
END;
The effects of SET LOCAL last only till the end of the current transaction.
The manual about SET LOCAL
.