【发布时间】:2021-09-28 05:02:34
【问题描述】:
我正在尝试了解 AT TIME ZONE 的行为,但在这方面我发现 SQL Server 和 PostgreSQL 之间存在一些奇怪的行为差异。
出于演示目的,我生成了两个查询,一个用于 SQL Server,一个用于 PostgreSQL。
SQL Server 查询:
SELECT
[LocalTime],
[LocalTime] AT TIME ZONE 'W. Europe Standard Time' AS [LocalTimeWithOffset],
([LocalTime] AT TIME ZONE 'W. Europe Standard Time') AT TIME ZONE 'UTC' AS [UniversalTime]
FROM
(VALUES
(CAST('2020-06-20 12:34:56.789' AS DATETIME2)),
(CAST('2020-12-20 12:34:56.789' AS DATETIME2))) AS [X] ([LocalTime])
产生这个结果(在 SQL Server Management Studio 中):
LocalTime LocalTimeWithOffset UniversalTime
--------- ------------------- ----------------
2020-06-20 12:34:56.7890000 2020-06-20 12:34:56.7890000 +02:00 2020-06-20 10:34:56.7890000 +00:00
2020-12-20 12:34:56.7890000 2020-12-20 12:34:56.7890000 +01:00 2020-12-20 11:34:56.7890000 +00:00
这对我来说似乎很好,因为我住在荷兰:在夏季,我们比 UTC 早 2 小时(由于夏令时),而在冬季,我们只比 UTC 早 1 小时。
但是... PostgreSQL 查询:
SELECT
"LocalTime",
"LocalTime" AT TIME ZONE 'WET' AS "LocalTimeWithOffset",
("LocalTime" AT TIME ZONE 'WET') AT TIME ZONE 'UTC' AS "UniversalTime"
FROM
(VALUES
(timestamp '2020-06-20 12:34:56.789'),
(timestamp '2020-12-20 12:34:56.789')) AS "X" ("LocalTime")
产生以下结果(在 pgAdmin 中):
LocalTime LocalTimeWithOffset UniversalTime
timestamp without time zone timestamp with time zone timestamp without time zone
--------------------------- ------------------------ ---------------------------
2020-06-20 12:34:56.789 2020-06-20 14:34:56.789+02 2020-06-20 12:34:56.789
2020-12-20 12:34:56.789 2020-12-20 13:34:56.789+01 2020-12-20 12:34:56.789
这对我来说似乎不正确。
在为此苦苦挣扎了一会儿之后,我想出了另一个 PostgreSQL 查询,它似乎产生了与 SQL Server 查询相同的结果:
SELECT
"LocalTime",
"LocalTime"::timestamptz AS "LocalTimeWithOffset",
"LocalTime"::timestamptz AT TIME ZONE 'UTC' AS "UniversalTime"
FROM
(VALUES
(timestamp '2020-06-20 12:34:56.789'),
(timestamp '2020-12-20 12:34:56.789')) AS "X" ("LocalTime")
但是这个查询似乎依赖于 PostgreSQL 服务器的时区。 :-(
是否有任何(最好是优雅的)方法来模拟 PostgreSQL 中的 SQL Server 逻辑/行为,而不依赖于服务器的时区(并在查询中使用明确指定的时区)?
编辑
我知道将 UTC 日期/时间值存储在数据库中并在呈现给最终用户时将它们(最好在客户端中/由客户端)转换为本地日期/时间值是一种很好的做法。当然,我也打算这样做,但我目前的情况是从 SQL Server 到 PostgreSQL 的数据库迁移(作为大型应用程序大修的一部分),其中 SQL Server 数据库中的 DATETIME2 表列包含本地日期/time 值,我想将其转换为 PostgreSQL 表中相应 timestamp 列中的 UTC 日期/时间值。我的迁移脚本可以很好地处理上面的查询,所以实际上我没有阻塞问题。提出这个问题的原因是,我只是对 SQL Server 和 PostgreSQL 在 AT TIME ZONE 行为方面的明显差异以及克服这些行为差异的方法感到好奇。
【问题讨论】:
-
您的
timezone设置是什么? -
@LaurenzAlbe 。 . .在 PostgreSQL 中执行
SHOW TIMEZONE会得到值CET。我猜那不是正确的时区... -
嗯,
timestamp with timezone的显示取决于您对timezone的设置。 -
@LaurenzAlbe 。 . .是啊。我想我知道你的意思。
timestamp with time zone类型的值不包含时区信息。这些值只是在内部存储为 UTC 日期/时间值。例如,当执行查询SELECT timestamptz '2020-12-20 12:00:00+02', timestamptz '2020-12-20 14:00:00+04'时,我会得到值2020-12-20 11:00:00+01和2020-12-20 11:00:00+01。与 SQL Server 的DATETIMEOFFSET数据类型相比,行为完全不同。我将对此进行更多研究。也许更改TIMEZONE设置会使我的最后一个查询“可配置”。 -
我会说
timestamp with timezone在 PostgreSQL 中的工作方式与在其他数据库中不同。我怀疑试图让他们表现得一样会失败,你必须有更广阔的视野。
标签: postgresql datetime-conversion postgresql-13