带时区的Postgres时间戳

问题描述 投票:0回答:2

我的“事件”表中有“事件日期时间”列,类型为“带时区的时间戳”。我的 python Flask 应用程序正在保存类似

'2014-08-30 02:17:02+00:00'
的日期,但 postgres 会自动将其转换为
'2014-08-30 07:17:02+05'
。它将时间戳转换为我的本地时区,即巴基斯坦。我想保存它而不转换。 我试过了

设置时区='UTC'

它确实将时区更改为“UTC”,但 pgadmin3 仍在保存转换后的时间。

我使用的是 MAC 操作系统和 Postgresql 9.3。

postgresql pgadmin postgresql-9.3
2个回答
22
投票

pgadmin 显示小时 +5 的原因是因为您的系统时区设置为这个。 当您在 GMT + 或 - 任何值保存“带有时区的时间戳”值时,系统会将您输入的任何时区偏移到 GMT(或 UTC),以便当您检索它时,您可以指定所需的时区它显示在。

例如,让我们确定纽约的当前时间。

select now()::timestamp with time zone at time zone 'America/New_York';

在询问时,它返回“2014-08-23 08:50:57.136817”。周六早上 8:50,如果你比较迂腐的话,那就是 8:51。

现在,如果我们采用相同的时间并以 GMT 显示它,我们将看到不同的结果:

select '2014-08-23 08:50:57.136817 America/New_York'::timestamp with time zone at time zone 'GMT';

现在有一个新时间“2014-08-23 12:50:57.136817”...进入“未来”5小时!

最后让我们获取原始时间戳并将其显示在我认为是巴基斯坦时区(PKT)的位置,看看它显示什么

select '2014-08-23 08:50:57.136817 America/New_York'::timestamp with time zone at time zone 'PKT';

结果呢? '2014-08-23 17:50:57.136817' 更进一步的未来!

我必须再次强调它能做到这一点的原因是因为它总是将输入时间偏移转换为 UTC 或 GMT。 Postgres 以这种方式处理其所有“带有时区的时间戳”数据类型。它旨在避免夏令时等时区问题。

您的问题似乎是 python 在+00 的偏移量处插入时间,如果这应该是当地时间,那么就 postgres 而言,您将需要 5 个小时的时间。在不确切知道 python 正在执行什么查询的情况下,我假设您可能想要查看它以确保它为您提供了正确的时间,大概

set timezone='PKT'
应该是一个解决方案。无论哪种方式,当您使用 pgadmin 等浏览器查看带有时区的时间戳时,时间戳都会转换为您的本地时区,这就是您看到 +5 的原因。

或者,如果您确实希望查看 +00 处的那些时间,则必须在 SELECT 查询中指定您想要的时间。


0
投票

在postgresql中,timestamptimestamptz始终存储在UTC中,两种类型具有相同的64位大小。

可以在当前会话/连接中设置时区,如下所示:

set timezone TO 'UTC';
set timezone TO 'America/New_York';
set timezone TO 'EST5EDT';
set timezone TO 'CEST-1CET';

Postgresql 使用

定义时区
  • 名称 - 如果在给定国家/地区使用夏令时
  • 缩写 - 仅带或不带夏令时
  • POSIX定义 - 夏令时可以任意定义

我在 postgres 中使用时间戳的规则:

  1. 在会话中设置 UTC 时区。
  2. 使用 UTC 时区中的 timestamp 进行存储。不要使用 timestamptz
  3. 根据 POSIX 使用时区定义,或者如果需要存储,可以命名并使用 varchar(64)。

Postgresql 中的 POSIX 时区格式

  • EST5EDT 与“美国/纽约”相同
  • AAA5AAA,M3.2.0/2:00:00,M11.1.0/2:00:00 与 'EST5EDT' 相同
  • CET-1CEST、M3.5.0、M10.5.0/3 是欧洲中部时间,采用完整格式的 DST

POSIX 格式说明:

  • EST5EDT 和 AAA5AAA - 中间的数字是相对于 GMT 的时间偏移,向西的所有内容都是正数,向东的所有内容都是负数(字母很可能被忽略,我不知道)
  • ,.M3 第三个月(三月)
  • .2.0 每月第二个星期日(例如:.1.1 每月第一个星期一)
  • /2:00:00时间
  • ,M11 第十一个月(十一月)
  • .1.0 每月第一个星期日
  • /2:00:00是时间

Postgres 时区函数:

时间戳加时间偏移EST5EDT

timezone('EST5EDT', timestamp) -- return type timestamptz

timestamptz 减去时间偏移 EST5EDT

timezone('EST5EDT', timestamptz) -- return type timestamp

示例:

时间戳转换为另一个时区

select
  'By name - America/New_York' as timezone_format,
  timezone('America/New_York', timestamp'2024-03-10 00:00:00') winter_dst,
  timezone('America/New_York', timestamp'2024-03-11 00:00:00') summer_dst
union all
select
  'by POSIX - EST5EDT' as timezone_format,
  timezone('EST5EDT', timestamp'2024-03-10 00:00:00') winter_dst,
  timezone('EST5EDT', timestamp'2024-03-11 00:00:00') summer_dst
union all
select
  'by POSIX full - AAA5AAA,M3...' as timezone_format,
  timezone('AAA5AAA,M3.2.0/2:00:00,M11.1.0/2:00:00', timestamp'2024-03-10 00:00:00') winter_dst,
  timezone('AAA5AAA,M3.2.0/2:00:00,M11.1.0/2:00:00', timestamp'2024-03-11 00:00:00') summer_dst;

结果:

set timezone to 'UTC'
+-----------------------------+--------------------------+--------------------------+
|timezone_format              |winter_dst                |summer_dst                |
+-----------------------------+--------------------------+--------------------------+
|By name - America/New_York   |2024-03-10 05:00:00 +00:00|2024-03-11 04:00:00 +00:00|
|by POSIX - EST5EDT           |2024-03-10 05:00:00 +00:00|2024-03-11 04:00:00 +00:00|
|by POSIX full - AAA5AAA,M3...|2024-03-10 05:00:00 +00:00|2024-03-11 04:00:00 +00:00|
+-----------------------------+--------------------------+--------------------------+

set timezone to 'EST5EDT';
+-----------------------------+--------------------------+--------------------------+
|timezone_format              |winter_dst                |summer_dst                |
+-----------------------------+--------------------------+--------------------------+
|By name - America/New_York   |2024-03-10 00:00:00 -05:00|2024-03-11 00:00:00 -04:00|
|by POSIX - EST5EDT           |2024-03-10 00:00:00 -05:00|2024-03-11 00:00:00 -04:00|
|by POSIX full - AAA5AAA,M3...|2024-03-10 00:00:00 -05:00|2024-03-11 00:00:00 -04:00|
+-----------------------------+--------------------------+--------------------------+

将时间戳转换为时间戳

select
  'by POSIX - use UTC' as timezone_format,
  timezone('EST5EDT', timestamptz'2024-03-10 00:00:00Z') winter_dst,
  timezone('EST5EDT', timestamptz'2024-03-11 00:00:00Z') summer_dst
union all
select
  'by POSIX - use session timezone' as timezone_format,
  timezone('EST5EDT', timestamptz'2024-03-10 00:00:00') winter_dst,
  timezone('EST5EDT', timestamptz'2024-03-11 00:00:00') summer_dst;

set timezone TO 'UTC';
+-------------------------------+-------------------+-------------------+
|timezone_format                |winter_dst         |summer_dst         |
+-------------------------------+-------------------+-------------------+
|by POSIX - use UTC             |2024-03-09 19:00:00|2024-03-10 20:00:00|
|by POSIX - use session timezone|2024-03-09 19:00:00|2024-03-10 20:00:00|
+-------------------------------+-------------------+-------------------+

set timezone TO 'EST5EDT';     
+-------------------------------+-------------------+-------------------+
|timezone_format                |winter_dst         |summer_dst         |
+-------------------------------+-------------------+-------------------+
|by POSIX - use UTC             |2024-03-09 19:00:00|2024-03-10 20:00:00|
|by POSIX - use session timezone|2024-03-10 00:00:00|2024-03-11 00:00:00|
+-------------------------------+-------------------+-------------------+
© www.soinside.com 2019 - 2024. All rights reserved.