【发布时间】:2016-12-16 03:05:02
【问题描述】:
如果我不想在服务器的时区中进行计算,那么将指定间隔添加到带有时区的时间戳的最佳方法是什么。这对于夏令时转换尤为重要。
例如
想想我们“向前冲”的那个晚上。 (在多伦多,我想是 2016 年 3 月 13 日凌晨 2 点)。
如果我记下时间戳:
2016-03-13 00:00:00-05
并添加'1 day' 到它,在加拿大/东部,我希望得到2016-03-14 00:00:00-04 -> 1 天后,但实际上只有 23 小时
但是如果我在萨斯喀彻温省(一个不使用 DST 的地方)增加 1 天,我希望它增加 24 小时,这样我最终会得到
2016-03-13 01:00:00-04.
如果我有列/变量
t1 timestamp with time zone;
t2 timestamp with time zone;
step interval;
zoneid text; --represents the time zone
其实我想说
t2 = t1 + step; --in a time zone of my choosing
Postgres 文档似乎表明带时区的时间戳在内部存储在 UTC 时间中,这似乎表明 timestamptz 列没有计算其中的时区。 SQL 标准表明 datetime + interval 操作应该保持第一个操作数的时区。
t2 = (t1 AT TIME ZONE zoneid + step) AT TIME ZONE zoneid;
似乎不起作用,因为第一次转换将 t1 转换为无时区时间戳,因此无法计算 DST 转换
t2 = t1 + step;
似乎不像在我的 SQL 服务器的时区中那样工作
操作前设置postgres时区,操作后改回来?
更好的说明:
CREATE TABLE timestamps (t1 timestamp with time zone, timelocation text);
SET Timezone 'America/Toronto';
INSERT INTO timestamps(t1, timelocation) VALUES('2016-03-13 00:00:00 America/Toronto', 'America/Toronto');
INSERT INTO timestamps(t1, timelocation) VALUES('2016-03-13 00:00:00 America/Regina', 'America/Regina');
SELECT t1, timelocation FROM timestamps; -- shows times formatted in Toronto time. OK
"2016-03-13 00:00:00-05";"America/Toronto"
"2016-03-13 01:00:00-05";"America/Regina"
SELECT t1 + '1 day', timelocation FROM timestamps; -- Toronto timestamp has advanced by 23 hours. OK. Regina time stamp has also advanced by 23 hours. NOT OK.
"2016-03-14 00:00:00-04";"America/Toronto"
"2016-03-14 01:00:00-04";"America/Regina"
如何解决这个问题?
a) 将 timestamptz 转换为适当时区的时间戳 tz?
SELECT t1 AT TIME ZONE timelocation + '1 day', timelocation FROM timestamps; --OK. Though my results are timestamps without time zone now.
"2016-03-14 00:00:00";"America/Toronto"
"2016-03-14 00:00:00";"America/Regina"
SELECT t1 AT TIME ZONE timelocation + '4 hours', timelocation FROM timestamps; -- NOT OK. I want the Toronto time to be 5am
"2016-03-13 04:00:00";"America/Toronto"
"2016-03-13 04:00:00";"America/Regina"
b) 更改 postgres 的时区并继续。
SET TIMEZONE = 'America/Regina';
SELECT t1 + '1 day', timelocation FROM timestamps; -- Now the Regina time stamp is correct, but toronto time stamp is incorrect (should be 22:00-06)
"2016-03-13 23:00:00-06";"America/Toronto"
"2016-03-14 00:00:00-06";"America/Regina"
SET TIMEZONE = 'America/Toronto';
SELECT t1 + '1 day', timelocation FROM timestamps; -- toronto is correct, regina is not, as before
"2016-03-14 00:00:00-04";"America/Toronto"
"2016-03-14 01:00:00-04";"America/Regina"
只有在每次操作时间间隔操作之前不断切换 postgres 时区时,此解决方案才有效。
【问题讨论】:
-
编辑:t1 和 t2 变量应该写成“带时区的时间戳”。抱歉,我是新来的,找不到编辑按钮。
-
如果答案解决了您的问题,您能否将其标记为已接受的答案? TIA。
标签: sql postgresql timezone plpgsql dst