gpt4 book ai didi

带时区的 Postgresql date_trunc 将时区移动 1 小时

转载 作者:行者123 更新时间:2023-11-29 11:40:18 27 4
gpt4 key购买 nike

我们正在使用 Postgresql 9.4,我注意到在使用 date_trunc 时有一个奇怪的行为。结果中的时区偏移 1 小时:

select date_trunc('year','2016-08-05 04:01:58.372486-05'::timestamp with time zone);
date_trunc
------------------------
2016-01-01 00:00:00-06

截断到例如天时没有这样的行为:

select date_trunc('day','2016-08-05 04:01:58.372486-05'::timestamp with time zone);
date_trunc
------------------------
2016-08-05 00:00:00-05

这是预期的行为吗?如果是这样,其背后的逻辑是什么?

最佳答案

date_trunc(text, timestamptz) 变体的文档似乎有点不足,所以这是我的发现:

1) 在day 精度(第一个参数)之下,结果的时区offset 始终与第二个参数的偏移量相同。

2) 在 day 精度或更高精度时,根据当前 TimeZone 配置参数(其中 can be setset time zone '...'set TimeZone to '...')。重新计算的偏移量始终与在 same TimeZone 配置参数生效的那个确切时间点上的偏移量相同。所以,f.ex。当 TimeZone 参数包含 DST 信息时,则相应地对齐偏移量。但是,当实际的 TimeZone 参数不包含 DST 信息(例如固定偏移量)时,结果的时区偏移量将保持不变。

总而言之,date_trunc(text, timestamptz) 函数可以用 date_trunc(text, timestamp) 变体和 at time 来模拟区域运算符s:

date_trunc('month', tstz)

应该等同于:

date_trunc('month', tstz at time zone current_setting('TimeZone')) at time zone current_setting('TimeZone'))

至少,我是这么想的。事实证明,有一些 TimeZone 配置设置存在问题。因为:

PostgreSQL allows you to specify time zones in three different forms:

  • A full time zone name, for example America/New_York. The recognized time zone names are listed in the pg_timezone_names view (see Section 50.80). PostgreSQL uses the widely-used IANA time zone data for this purpose, so the same time zone names are also recognized by much other software.

  • A time zone abbreviation, for example PST. Such a specification merely defines a particular offset from UTC, in contrast to full time zone names which can imply a set of daylight savings transition-date rules as well. The recognized abbreviations are listed in the pg_timezone_abbrevs view (see Section 50.79). You cannot set the configuration parameters TimeZone or log_timezone to a time zone abbreviation, but you can use abbreviations in date/time input values and with the AT TIME ZONE operator.

(第三个是固定偏移量,或者它的 POSIX 形式,但这在这里并不重要)。

如您所见,abbreviations 不能设置为 TimeZone。但是有一些缩写,也被认为是完整时区名称,f.ex。 英语考试。因此,set time zone 'CET' 会成功,但实际上会在夏令时使用 CEST。但是 at time zone 'CET' 将始终引用 abbreviation,它是 UTC 的固定偏移量(永远不会 CEST,因为可以使用 at time zone 'CEST';但 set time zone 'CEST' 无效。

这是时区设置的完整列表,当它们用于 set time zone 与用于 at time zone 时具有不兼容的含义(从 9.6 开始):

CET
EET
MET
WET

使用以下脚本,您可以检查您的版本:

create or replace function incompatible_tz_settings()
returns setof text
language plpgsql
as $func$
declare
cur cursor for select name from pg_timezone_names;
begin
for rec IN cur loop
declare
r pg_timezone_names;
begin
r := rec;
execute format('set time zone %L', (r).name);
if exists(select 1
from generate_series(current_timestamp - interval '12 months', current_timestamp + interval '12 months', interval '1 month') tstz
where date_trunc('month', tstz) <> date_trunc('month', tstz at time zone (r).name) at time zone (r).name) then
return next (r).name;
end if;
end;
end loop;
end
$func$;

http://rextester.com/GBL17756

关于带时区的 Postgresql date_trunc 将时区移动 1 小时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38785924/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com