问题
I am running PostgreSQL 9.6.6 on x86_64-pc-linux-gnu and my time zone is set to 'UTC'.
Does anyone know why the results of the following SELECT
statements are different?
A)
SELECT timezone('EST', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
B)
SELECT timezone('-05', '2017-12-21');
timezone
---------------------
2017-12-21 05:00:00
According to the pg_timezone_names
table -05
should have the same offset as EST
... Any thoughts? Thanks.
回答1:
https://www.postgresql.org/docs/current/static/view-pg-timezone-names.html
The view pg_timezone_names provides a list of time zone names that are recognized by SET TIMEZONE
and further:
utc_offset interval Offset from UTC (positive means east of Greenwich)
when you set timezone to 'EST'
- you declare that your client is in EST time zone, thus returned time will be adjusted for your tz:
t=# select '2017-12-21'::timestamptz;
timestamptz
------------------------
2017-12-21 00:00:00-05
(1 row)
the interval match utc_offset from pg_timezone_names
and isequal -05
, so it works as expected. (indeed in EST will be 5 hours less then UTC) same result if you set timezone to '-05'
.
Both -05
and EST
give same result for SET TIMEZONE
as described in docs.
Now you answer reconciles with docs on using interval
: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-ZONECONVERT
In these expressions, the desired time zone zone can be specified either as a text string (e.g., 'PST') or as an interval (e.g., INTERVAL '-08:00').
following these rules it works as well:
t=# select '2017-12-21'::timestamptz at time zone 'EST';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
t=# select '2017-12-21'::timestamptz at time zone interval '-05:00';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
but further, docs say:
In the text case, a time zone name can be specified in any of the ways described in Section 8.5.3.
which is https://www.postgresql.org/docs/current/static/datatype-datetime.html#DATATYPE-TIMEZONES
PostgreSQL allows you to specify time zones in three different forms:
- recognized time zone names are listed in the pg_timezone_names
- recognized abbreviations are listed in the pg_timezone_abbrevs
- POSIX-style time zone specifications of the form STDoffset or STDoffsetDST
(formatting mine)
and lastly:
One should be wary that the POSIX-style time zone feature can lead to silently accepting bogus input...Another issue to keep in mind is that in POSIX time zone names, positive offsets are used for locations west of Greenwich. Everywhere else, PostgreSQL follows the ISO-8601 convention that positive timezone offsets are east of Greenwich.
TL;DR
So in short - when you define '-05' as text (not interval) input for timezone()
function or AT TIME ZONE
directive (effectively same) Postgres thinks this is an attempt to use POSIX style time zone and thus inverts sign, thus you get "opposite" result...
a simple demonstration of this documented inversion:
t=# select '2017-12-21'::timestamptz at time zone '05';
timezone
---------------------
2017-12-20 19:00:00
(1 row)
回答2:
Okay I think I found an answer to my own question:
According to the PostgreSQL docs, section 9.9.3 at the following link https://www.postgresql.org/docs/9.6/static/functions-datetime.html
In these expressions, the desired time zone zone can be specified either as a text string (e.g., 'PST') or as an interval (e.g., INTERVAL '-08:00'). In the text case, a time zone name can be specified in any of the ways described in Section 8.5.3.
So using the INTERVAL
syntax, the following appears to work:
SELECT timezone(INTERVAL '-05:00', '2017-12-21');
timezone
---------------------
2017-12-20 19:00:00
I think it is still curious, what exactly SELECT timezone('-05', '2017-12-21');
means, as the following also provides the expected result (with the addition of a TZ offset):
SELECT timezone('-05', '2017-12-21'::timestamp);
timezone
------------------------
2017-12-20 19:00:00+00
来源:https://stackoverflow.com/questions/48013068/postgresql-timezone-conversion-est-05