Postgres 9.6,时区:为什么这两个查询给我不同的时间
Postgres 9.6, timezones: why are those two queries giving me different times
好吧,我一直对时区感到困惑。我正在好转,但还没有。各位大神能赐教吗?
上下文:我从前端收到 UTC 时间。例如,要表示日期 1 September 2019
,我会得到 2019-08-31 22:00:00Z
(我们在布鲁塞尔夏令时,因此有 2 小时的时差)。
从那个日期开始,我需要生成之前 6 个月的系列。那就是 March April May June July August
.
我设法找到了解决方案,老实说有点不走运。我仍然不确定我是否理解下面发生的事情的细节:
database=> show timezone;
TimeZone
----------
UTC
(1 row)
database=> select generate_series(
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-02-28 00:00:00
2019-03-28 00:00:00
2019-04-28 00:00:00
2019-05-28 00:00:00
2019-06-28 00:00:00
2019-07-28 00:00:00
(6 rows)
database=> select generate_series(
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-03-01 00:00:00
2019-04-01 00:00:00
2019-05-01 00:00:00
2019-06-01 00:00:00
2019-07-01 00:00:00
2019-08-01 00:00:00
为什么我使用 ::timestamp
会得到错误的结果?
实际上有两种名为 AT TIME ZONE
的不同“运算符”,一种将 timestamp with time zone
转换为 timestamp without time zone
,另一种则相反。
如果第一个参数是 timestamp with time zone
,该值将转换为 timestamp without time zone
,显示该时区的挂钟。
如果第一个参数是 timestamp without time zone
,它在会话时区(由 timezone
参数的值给出)中解释并转换为绝对时间戳。
现在 timestamp with time zone
是 date/time 类型类别 的 首选类型 ,因此字符串文字在根据 the documentation,您的第二个查询被解释为 timestamp with time zone
。在第一个查询中它是 timestamp without time zone
。由于涉及到不同的运算符,结果不同也就不足为奇了。
在您的第一个查询中,挂钟时间 22:00 被解释为好像挂在布鲁塞尔的时钟,所以它实际上是 20:00 UTC。 generate_series
的第一个参数,从这里开始计数,然后是 2019 年 2 月 28 日,20:00 UTC(在转换为 date
之前)。
好吧,我一直对时区感到困惑。我正在好转,但还没有。各位大神能赐教吗?
上下文:我从前端收到 UTC 时间。例如,要表示日期 1 September 2019
,我会得到 2019-08-31 22:00:00Z
(我们在布鲁塞尔夏令时,因此有 2 小时的时差)。
从那个日期开始,我需要生成之前 6 个月的系列。那就是 March April May June July August
.
我设法找到了解决方案,老实说有点不走运。我仍然不确定我是否理解下面发生的事情的细节:
database=> show timezone;
TimeZone
----------
UTC
(1 row)
database=> select generate_series(
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-02-28 00:00:00
2019-03-28 00:00:00
2019-04-28 00:00:00
2019-05-28 00:00:00
2019-06-28 00:00:00
2019-07-28 00:00:00
(6 rows)
database=> select generate_series(
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-03-01 00:00:00
2019-04-01 00:00:00
2019-05-01 00:00:00
2019-06-01 00:00:00
2019-07-01 00:00:00
2019-08-01 00:00:00
为什么我使用 ::timestamp
会得到错误的结果?
实际上有两种名为 AT TIME ZONE
的不同“运算符”,一种将 timestamp with time zone
转换为 timestamp without time zone
,另一种则相反。
如果第一个参数是 timestamp with time zone
,该值将转换为 timestamp without time zone
,显示该时区的挂钟。
如果第一个参数是 timestamp without time zone
,它在会话时区(由 timezone
参数的值给出)中解释并转换为绝对时间戳。
现在 timestamp with time zone
是 date/time 类型类别 的 首选类型 ,因此字符串文字在根据 the documentation,您的第二个查询被解释为 timestamp with time zone
。在第一个查询中它是 timestamp without time zone
。由于涉及到不同的运算符,结果不同也就不足为奇了。
在您的第一个查询中,挂钟时间 22:00 被解释为好像挂在布鲁塞尔的时钟,所以它实际上是 20:00 UTC。 generate_series
的第一个参数,从这里开始计数,然后是 2019 年 2 月 28 日,20:00 UTC(在转换为 date
之前)。