我有一个包含数据类型为timestamp without time zone
的列的表,我正在尝试将其转换为在给定时区没有时区的时间戳。
这些是我的Postgres 9.3设置
select current_setting('TIMEZONE');
current_setting
-----------------
Hongkong
select * from pg_timezone_names where name = 'Hongkong';
name | abbrev | utc_offset | is_dst
----------+--------+------------+--------
Hongkong | HKT | 08:00:00 | f
以下是我将其转换为HKT所做的工作:
-- this SQL gives me what I expected
select '2015-01-05 12:00:00'::timestamp without time zone
at time zone 'UTC'
at time zone 'HKT';
---------------------
2015-01-05 20:00:00
-- Shouldn't this produce the same result with the above one?
-- How do I make this work?
-- Don't tell me to change it to UTC-08:00 ...
select '2015-01-05 12:00:00'::timestamp without time zone
at time zone 'UTC'
at time zone 'UTC+08:00';
---------------------
2015-01-05 04:00:00 -- WHY?
答案 0 :(得分:2)
这背后的原因是你真的不应该在PostgreSQL中使用时区偏移(除非你确切知道你做了什么)。
时区'UTC+08:00'
是POSIX风格的时区规范,'Hongkong'
是确切的时区名称,'HKT'
是其中一个(缩写)的缩写。< / p>
pg_timezone_names
系统视图的utc_offset
列defined为 UTC的偏移量(正数表示格林威治的东)
但在POSIX风格的时区规范中,偏移部分为different:
...要记住的另一个问题是,在POSIX时区名称中,正偏移用于格林威治的 west 位置。在其他地方,PostgreSQL遵循ISO-8601惯例,即格林威治的正时区偏移 east 。
因此,您应该使用:
,而不是使用偏移量(作为间隔)或POSIX样式的时区规范。简而言之,这是缩写和全名之间的区别:缩写表示与UTC的特定偏移,而许多全名意味着本地夏令时规则,因此有两个可能的UTC偏移。
为了使问题复杂化,一些司法管辖区使用相同的时区缩写来表示不同时间的不同UTC偏移;例如,在莫斯科,MSK在某些年份意味着UTC + 3,在其他年份意味着UTC + 4。 PostgreSQL根据它们在指定日期的意思(或最近意味着)解释这些缩写;但是,与上面的EST示例一样,这不一定与该日的当地民事时间相同。
但最简单的解决方案是使用timestamp with time zone
:您已将TimeZone
设置为'Hongkong'
,因此timestamp with time zone
值会在该时区显示给您(PostgreSQL)客户端。
set time zone 'Hongkong';
select current_setting('TimeZone') TimeZone,
dt original,
dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC+08:00' "UTC+08:00",
dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC+8' "UTC+8",
dt AT TIME ZONE 'UTC' AT TIME ZONE 'UTC-8' "UTC-8",
dt AT TIME ZONE 'UTC' AT TIME ZONE INTERVAL '+08:00' "INTERVAL +08:00",
dt AT TIME ZONE 'UTC' AT TIME ZONE 'HKT' "HKT",
dt AT TIME ZONE 'UTC' AT TIME ZONE 'Hongkong' "Hongkong",
dt AT TIME ZONE 'UTC' "with time zone"
from (values (timestamp '2015-01-05 12:00:00')) v(dt);
-- TIMEZONE | ORIGINAL | UTC+08:00
-- ---------+---------------------+--------------------
-- Hongkong | 2015-01-05 12:00:00 | 2015-01-05 04:00:00
-- UTC+8 | UTC-8 | INTERVAL +08:00
-- --------------------+---------------------+--------------------
-- 2015-01-05 04:00:00 | 2015-01-05 20:00:00 | 2015-01-05 20:00:00
-- HKT | HONGKONG | WITH TIME ZONE
-- --------------------+---------------------+-----------------------
-- 2015-01-05 20:00:00 | 2015-01-05 20:00:00 | 2015-01-05 20:00:00+08