将不带时区的时间戳转换为带时区的时间戳
Convert timestamp without timezone into timestamp with timezone
我有一个类型为 nullable timestamp without time zone
的列。它以这种格式存储在我的 Postgres 数据库中:2021-06-24 11:00:00
。我想将其转换为可为 null 的 timestamp with time zone
类型,以便显示为 2021-06-24 11:00:00.000-00
。请注意,没有时区转换。
该解决方案还应允许从 timestamp with time zone
转换为 timestamp without time zone
。我做了一些研究,但找不到任何东西。
您正在寻找 AT TIME ZONE,这有点令人困惑,但可以满足您的所有需求。
要将已知为 UTC 的时间戳转换为 timestamptz:
SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC';
=> 2021-06-24 06:00:00-05
所有 timestamptz 值都以 UTC 格式内部存储在 Postgres 中,并且不保留它们插入时所在的时区,因此它们将显示在您的连接时区中。您可以再次使用 AT TIME ZONE
将 timestamptz 转换回所需区域中的时间戳(正如 Erwin 在下面指出的那样,AT TIME ZONE
总是在 timestamp 和 timestamptz 之间切换):
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';
=> 2021-06-24 11:00:00
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'America/Chicago';
=> 2021-06-24 06:00:00
假设 table tbl
具有时间戳列 ts
和表示 UTC 时间的时间戳,解决方案是:
ALTER TABLE tbl ALTER COLUMN ts type timestamptz USING ts AT TIME ZONE 'UTC';
db<>fiddle here
您可能还需要调整列默认值。参见:
误解1(问题)
I have a column that is of type nullable timestamp without time zone.
It is stored in my Postgres database in this format: 2021-06-24 11:00:00
.
timestamp
or timestamptz
值永远不会以任何格式存储。格式化属于 显示 的范围,并且在很大程度上独立于存储类型。存储的是一个 8 字节的整数,精度为微秒,代表一个时间点。您显示的显示是使用 ISO 8601 的标准 Postgres 文本表示(对于输入也是明确的)。使用二进制协议的客户端可能会选择不同的表示形式。即使是使用文本协议的客户端也可能会选择以不同方式重新格式化。
误区二(问题)
I would like to convert it to a nullable timestamp with time zone type
such that it would be displayed as 2021-06-24 11:00:00.000-00
.
显示的时间偏移不是由数据类型决定的。如果当前 TimeZone
setting(通常为 UTC)为真,您只会看到附加的时区 -00
。否则,您会得到不同的偏移量,并且时间戳会相应地移动。
误区三(答案)
To represent it in UTC (the output value here looks like it has no
timezone, but the type is timestamptz):
SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC' AT TIME
ZONE 'UTC';
=> 2021-06-24 11:00:00
不是,输出值的类型是timestamp
。 timestamptz
在默认文本表示中永远不会“看起来”像 timestamp
。 timestamp
从来没有“拥有”时区。甚至 timestamptz
“没有”时区,它只是显示 for 给定的时区。这两种类型都不存储任何时区信息。参见:
误区四(答案)
To cast a timestamptz back to a timestamp at UTC time:
SELECT ('2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC')::timestamp;
=> 2021-06-24 11:00:00
没有。只是:
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';
结果类型为 timestamp
。没有额外演员。
AT TIME ZONE
construct 在 timestamp
和 timestamptz
之间转换。结果类型总是从输入切换。
这里是基础知识:
- Ignoring time zones altogether in Rails and PostgreSQL
我有一个类型为 nullable timestamp without time zone
的列。它以这种格式存储在我的 Postgres 数据库中:2021-06-24 11:00:00
。我想将其转换为可为 null 的 timestamp with time zone
类型,以便显示为 2021-06-24 11:00:00.000-00
。请注意,没有时区转换。
该解决方案还应允许从 timestamp with time zone
转换为 timestamp without time zone
。我做了一些研究,但找不到任何东西。
您正在寻找 AT TIME ZONE,这有点令人困惑,但可以满足您的所有需求。
要将已知为 UTC 的时间戳转换为 timestamptz:
SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC';
=> 2021-06-24 06:00:00-05
所有 timestamptz 值都以 UTC 格式内部存储在 Postgres 中,并且不保留它们插入时所在的时区,因此它们将显示在您的连接时区中。您可以再次使用 AT TIME ZONE
将 timestamptz 转换回所需区域中的时间戳(正如 Erwin 在下面指出的那样,AT TIME ZONE
总是在 timestamp 和 timestamptz 之间切换):
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';
=> 2021-06-24 11:00:00
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'America/Chicago';
=> 2021-06-24 06:00:00
假设 table tbl
具有时间戳列 ts
和表示 UTC 时间的时间戳,解决方案是:
ALTER TABLE tbl ALTER COLUMN ts type timestamptz USING ts AT TIME ZONE 'UTC';
db<>fiddle here
您可能还需要调整列默认值。参见:
误解1(问题)
I have a column that is of type nullable timestamp without time zone. It is stored in my Postgres database in this format:
2021-06-24 11:00:00
.
timestamp
or timestamptz
值永远不会以任何格式存储。格式化属于 显示 的范围,并且在很大程度上独立于存储类型。存储的是一个 8 字节的整数,精度为微秒,代表一个时间点。您显示的显示是使用 ISO 8601 的标准 Postgres 文本表示(对于输入也是明确的)。使用二进制协议的客户端可能会选择不同的表示形式。即使是使用文本协议的客户端也可能会选择以不同方式重新格式化。
误区二(问题)
I would like to convert it to a nullable
timestamp with time zone type
such that it would be displayed as2021-06-24 11:00:00.000-00
.
显示的时间偏移不是由数据类型决定的。如果当前 TimeZone
setting(通常为 UTC)为真,您只会看到附加的时区 -00
。否则,您会得到不同的偏移量,并且时间戳会相应地移动。
误区三(答案)
To represent it in UTC (the output value here looks like it has no timezone, but the type is timestamptz):
SELECT '2021-06-24 11:00:00'::timestamp AT TIME ZONE 'UTC' AT TIME ZONE 'UTC'; => 2021-06-24 11:00:00
不是,输出值的类型是timestamp
。 timestamptz
在默认文本表示中永远不会“看起来”像 timestamp
。 timestamp
从来没有“拥有”时区。甚至 timestamptz
“没有”时区,它只是显示 for 给定的时区。这两种类型都不存储任何时区信息。参见:
误区四(答案)
To cast a timestamptz back to a timestamp at UTC time:
SELECT ('2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC')::timestamp; => 2021-06-24 11:00:00
没有。只是:
SELECT '2021-06-24 11:00:00-00'::timestamptz AT TIME ZONE 'UTC';
结果类型为 timestamp
。没有额外演员。
AT TIME ZONE
construct 在 timestamp
和 timestamptz
之间转换。结果类型总是从输入切换。
这里是基础知识:
- Ignoring time zones altogether in Rails and PostgreSQL