The difference between TIMESTAMP WITHOUT TIME ZONE
and TIMESTAMP WITH TIME ZONE
(TIMESTAMPTZ
) can be quite tricky to understand if you consider their names. (In fact, the specifications seem to be sufficiently confusing so that various RDBMS implement it in a different way.)
In PostgreSQL, neither types store the time zone of the value when it was stored, but TIMESTAMPTZ
stores the value as a precise instant in time based on the UTC reference, whereas TIMESTAMP WITHOUT TIME ZONE
is always relative.
- When queried, a
TIMESTAMPTZ
will be adjusted to represent the same instant in time as initially stored (in whichever part of the world this was) as the instant it would be in the current time zone as configured by the client.
- A
TIMESTAMP WITHOUT TIME ZONE
will always be the same value relative to the time zone configured by the client, even if the time zone where you query it from differs: the instant represented by 2013-11-03 03:00:00
will be ambiguous and depend on the client settings.
Presumably, you used your "timezone" column (P
or M
) with your TIMESTAMP WITHOUT TIME ZONE
to compensate for the ambiguity in the input value.
In principle, if you are in the same relative time zone as the one where you stored the timestamp, you should get the same value back, so if you've set your client in the US/Pacific
time zone and if you've stored 2013-11-03 03:00:00
in your P
time zone, you should get 2013-11-03 03:00:00
back. However, this is only valid when there is no ambiguity in the relative value.
The problem here in your first example is that there already is some ambiguity:
timestamp: 2013-11-03 01:00:00 timezone: "P" would become: 2013-11-03
01:00:00-07
2013-11-03 01:00:00
can represent two distinct instants in time in the US/Pacific
time zone, so with just 2013-11-03 01:00:00
and "P"
, you've already lost information that you won't be able to recover.
If you just wanted it to change between '-08' and '-07' depending on the DST setting at that instant in time, this would have been done for you automatically, but you should have use a TIMESTAMPTZ
in the first place, to be precise on which instant in time you were representing.
Here is an example where the initial time zone is kept, so you can see the change between '-08' and '-07':
SET time zone 'US/Pacific';
SELECT t AS "Date/Time for US/Pacific",
t AT time zone 'UTC' "Date/Time in UTC"
FROM (VALUES
('2013-11-03 00:00:00-07'::timestamptz),
('2013-11-03 01:00:00-07'::timestamptz),
('2013-11-03 02:00:00-07'::timestamptz),
('2013-11-03 03:00:00-07'::timestamptz)) AS v(t);
Results:
| DATE/TIME FOR US/PACIFIC | DATE/TIME IN UTC |
|--------------------------|---------------------|
| 2013-11-03 00:00:00-07 | 2013-11-03 07:00:00 |
| 2013-11-03 01:00:00-07 | 2013-11-03 08:00:00 |
| 2013-11-03 01:00:00-08 | 2013-11-03 09:00:00 |
| 2013-11-03 02:00:00-08 | 2013-11-03 10:00:00 |
Unfortunately, there is no way to handle DST change with just your two fields.
It's certainly worth reading the Date/Time types section of the PostgreSQL manual, as well as paying attention to the "return types" column of the table in the AT TIME ZONE
documentation for a better understanding of these problems.