如何 select timestamptz with offset with AT TIME ZONE

How to select timestamptz with offset with AT TIME ZONE

我一直在摆弄 PostgreSQL 中的时间戳,阅读了关于此行为的有趣 Blog,但不知道如何解决以下问题:

如何在 select 一个 'timestamp with time zone' 列中包含来自另一列的 AT TIME ZONE,一步包括到 UTC 的偏移量?

我在 PostgreSQL 10 中有一个示例 table:

CREATE TABLE public.test_tz
(
    id serial,
    in_zone_timestamp timestamp without time zone,
    in_zone character varying COLLATE pg_catalog."default",
    CONSTRAINT test_tz_pkey PRIMARY KEY (id)
)
WITH (
    OIDS = FALSE
)
TABLESPACE pg_default;

PostgreSQL 的设置是

timezone=localtime

并且服务器运行在 'Europe/Berlin'

$ date --> Fri Mar 9 12:15:23 CET 2018

时间戳列应该使用这种混乱的语法存储:

INSERT INTO public.test_tz ( in_zone_timestamp, in_zone) VALUES
('2017-02-01 00:00:00' AT TIME ZONE current_setting('TIMEZONE') AT TIME ZONE 'Asia/Singapore', 'Asia/Singapore' );

如果有人知道更好的方法,请不要犹豫!另一种解决方案是使用'2017-02-01 00:00:00-08'作为值,但我不知道偏移值

我想像这样存储本地时间戳:'The user hit a key at 2017-02-01 00:00:00 in Singapore'。

如果我询问数据库:它是在欧洲的哪个时间,当新加坡的用户按下一个键时,我得到:

SELECT in_zone_timestamp FROM public.test_tz;
--> '2017-01-31 17:00:00+01'

这似乎还可以,因为新加坡有 +8 小时的偏移量。

如果我想知道在新加坡的时间,我使用:

SELECT in_zone_timestamp AT TIME ZONE in_zone FROM public.test_tz;
--> '2017-02-01 00:00:00'

也可以,但是,它没有 return 到 'UTC' 的偏移量,所以我看不出这个时间戳不是我的本地时间!

我尝试了一些 AT TIME ZONE 或转换为 timestamptz 的组合,但结果不是我想要的。我期望这样的结果:

--> '2017-02-01 00:00:00+08'

在这里,我只看到一个解决方案,手动 concat/convert/manipulate 结果并手动添加偏移量,但这是唯一的方法吗?

对不起,如果我解释这个问题有点过于复杂,希望有人能理解我的想法。

提前致谢

让 PostgreSQL 自动将时间戳转换为类似 2017-02-01 00:00:00+08 的字符串的唯一方法是更改​​会话时区:

SET timezone = 'Asia/Singapore';

您可以使用 SET LOCAL 仅在交易期间更改设置。

如果您不想这样,您可以通过如下查询获取偏移量:

SELECT TIMESTAMP '2000-01-01 00:00:00' AT TIME ZONE 'UTC'
     - TIMESTAMP '2000-01-01 00:00:00' AT TIME ZONE 'Asia/Singapore';

 ?column? 
----------
 08:00:00
(1 row)

感谢您的澄清,但我认为 PostgreSQL 在这个主题上有一些缺点。

这个问题的'not so perfect'解决方案实际上是手动连接所需的部分。

SELECT (test_tz.in_zone_timestamp AT TIME ZONE in_zone) || (SELECT abbrev FROM pg_timezone_names WHERE name = in_zone)  FROM public.test_tz;
--> 2017-02-01 00:00:00+08

这提供了一个可以接受的解决方案,但有一些小瑕疵。

在某些情况下,abbrev-column 中有时区短文本,如 'CET' 或 'PDT' 而不是 +/- 数值。这会产生如下结果(例如 'Europe/Berlin'):

--> 2017-02-01 02:00:00CET

一个更好的值给pg-timezone-names的第'utc_offset'列,但这需要更复杂的文本操作,我现在不想要。

第二种解决方案可以是通过应用程序操纵输出并将文本格式化为您需要的任何格式。

希望能帮助其他人解决此类问题,而无需在互联网上搜索数据库中不可用的支持。

再见