我有一张没有时区的时间戳表。 YYYY-MM-DD HH:MM:SS
和一个字段“timezone”,对于Pacific来说是“P”,对于Mountain来说是“M”。
我需要创建一个“带时区的时间戳”字段
鉴于我有两个字段,有没有办法正确地解释夏令时?
具体做法是: 时间戳:2013-11-03 01:00:00 时区:“P” 将成为:2013-11-03 01:00:00-07
和 时间戳:2013-11-03 03:00:00 时区:“P” 将成为:2013-11-03 03:00:00-08
答案 0 :(得分:1)
首先,当说结果将成为例如2013-11-03 01:00:00-07
时,应该补充说这实际上取决于SQL客户端的时区设置。例如,欧洲时段的会话永远不会将2013-11-03 01:00:00-07
视为timestamp with time zone
的值,因为没有欧洲国家/地区GMT-07
。
也就是说,可以使用应用于timestamp without time zone
的{{3}}构造进行转换。
假设我们从US/Pacific
时区运行:
SET time zone 'US/Pacific';
SELECT t AT TIME ZONE
case z when 'P' then 'US/Pacific' when 'M' then 'US/Mountain' end
from (values
('2013-11-03 01:00:00'::timestamp, 'P'),
('2013-11-03 03:00:00'::timestamp, 'P')
) as v(t,z);
结果是:
timezone ------------------------ 2013-11-03 01:00:00-08 2013-11-03 03:00:00-08
2013-11-03 01:00:00 AT time zone 'US/Pacific'
有歧义,因为它属于-07
时区中首先发生的小时跨度,然后是DST切换后-08
时区中的第二次。对postgres的解释是在-08
时区看到它。如果我们考虑前一分钟,它会落入-07
时区。
答案 1 :(得分:1)
如果您考虑他们的名字,TIMESTAMP WITHOUT TIME ZONE
和TIMESTAMP WITH TIME ZONE
(TIMESTAMPTZ
)之间的区别可能非常棘手。 (事实上,规范似乎足够混乱,因此各种RDBMS以不同的方式实现它。)
在PostgreSQL中,两种类型都不存储值存储时的时区,但TIMESTAMPTZ
根据UTC引用将值存储为精确的时刻,而TIMESTAMP WITHOUT TIME ZONE
始终是相对的
TIMESTAMPTZ
将被调整为代表与最初存储的时间相同的时刻(在世界的任何一个地方),就像它在当前时区中所设置的瞬间一样。客户端。TIMESTAMP WITHOUT TIME ZONE
始终是相同的值,即使您查询它的时区不同:2013-11-03 03:00:00
表示的时刻也不明确,取决于客户端设置。据推测,您使用“{时区”列(P
或M
)和TIMESTAMP WITHOUT TIME ZONE
来补偿输入值中的歧义。< / p>
原则上,如果您与存储时间戳的时区位于相同的时区,则应该返回相同的值,因此如果您将客户端设置为US/Pacific
时区并且如果您已将2013-11-03 03:00:00
存储在P
时区,则应返回2013-11-03 03:00:00
。但是,这仅在相对值没有歧义时才有效。
你的第一个例子中的问题是已经存在一些含糊之处:
时间戳:2013-11-03 01:00:00时区:“P”将成为:2013-11-03 01:00:00-07
2013-11-03 01:00:00
可以代表US/Pacific
时区中两个不同的时刻,因此只有2013-11-03 01:00:00
和"P"
,您已经丢失了您赢得的信息'能够恢复。
如果您只是希望它在'-08'和'-07'之间切换,具体取决于该时刻的DST设置,这将自动为您完成,但您应该使用{{1}首先,确切地说,你代表的是哪个时刻。
以下是保留初始时区的示例,因此您可以看到'-08'和'-07'之间的变化:
TIMESTAMPTZ
结果:
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);
不幸的是,只有两个字段无法处理DST更改。
当然值得阅读Date/Time types section of the PostgreSQL manual,并注意AT TIME ZONE
documentation中表格的“返回类型”列,以便更好地理解这些问题。
答案 2 :(得分:0)
检查这是否对您有意义
set timezone to 'PST8PDT';
select now();
now
-------------------------------
2013-09-28 03:24:20.169189-07
select ts,
ts at time zone 'PST' as "PST",
ts at time zone 'PDT' as "PDT"
from (values
('2013-11-03 01:00:00'::timestamp),
('2013-11-03 02:00:00'),
('2013-11-03 03:00:00')
) s (ts)
;
ts | PST | PDT
---------------------+------------------------+------------------------
2013-11-03 01:00:00 | 2013-11-03 01:00:00-08 | 2013-11-03 01:00:00-07
2013-11-03 02:00:00 | 2013-11-03 02:00:00-08 | 2013-11-03 01:00:00-08
2013-11-03 03:00:00 | 2013-11-03 03:00:00-08 | 2013-11-03 02:00:00-08