如何获得所有相同的日期和时间独立于时区

时间:2012-02-04 16:17:16

标签: php sql postgresql

我应该如何在PostgreSQL数据库中存储“date + times”?

这就是我想要实现的目标:

  1. 如何在当地时间2012年1月1日00:00:00(例如)世界任何地方发生所有条目?
  2. 根据UTC时间显示按日期排序的所有条目。 (2012年纽约新年前夜比伦敦新年更近)。
  3. 我应该如何存储数据?我已经读过PostgreSQL内部存储所有时间(PostgreSQL documentation),所以我的用户时区实际上已经丢失了。

    我想我应该使用一个类型为“timestamp without timezone”的列:

    • 第1点很容易。
    • 使用另一个类型为“String”的列,我将存储时区字符串(例如:America / New_York) 但是,第2点看起来仍然很难....

    我希望我很清楚。

    编辑新想法:我认为存储两个时间戳:一个没有时区(1. ok),一个带时区(2. ok)

2 个答案:

答案 0 :(得分:1)

是的,PostgreSQL在内部将所有时间戳存储为UTC。对于timestamp with time zone,时区偏移仅适用于调整UTC时间,但不会显式存储。

我不会存储时区字符串,甚至不会存储时区缩写(这些都不准确)。这可以在以后需要昂贵的计算,因为你必须考虑夏令时和国际时间制度的其他奇怪之处。

你可以将时区偏移量存储为间隔(取 12字节)或数字秒数(取 4字节作为整数),就像我在此演示一样related answer

或者,就像您已经建议的那样:除了UTC时间戳之外还存储本地时间戳(需要 8个字节)。这将使您的任务变得简单。考虑以下demo ::

-- DROP TABLE tbl;
CREATE TEMP TABLE tbl (id int, ts_tz timestamp with time zone, ts timestamp);
INSERT INTO tbl VALUES
 (1,'2012-1-1 00:00+01','2012-1-1 00:00+01')
,(2,'2012-1-1 00:00+02','2012-1-1 00:00+02')
,(3,'2012-1-1 00:01+03','2012-1-1 00:01+03')
,(4,'2012-1-1 00:02+04','2012-1-1 00:02+04');

查询问题1:

SELECT *
FROM   tbl
WHERE  ts = '2012-1-1 00:00'::timestamp;

 id |         ts_tz          |         ts
----+------------------------+---------------------
  1 | 2012-01-01 00:00:00+01 | 2012-01-01 00:00:00
  2 | 2011-12-31 23:00:00+01 | 2012-01-01 00:00:00

查询问题2:

SELECT *
FROM   tbl
ORDER  BY ts_tz;

 id |         ts_tz          |         ts
----+------------------------+---------------------
  4 | 2011-12-31 21:02:00+01 | 2012-01-01 00:02:00
  3 | 2011-12-31 22:01:00+01 | 2012-01-01 00:01:00
  2 | 2011-12-31 23:00:00+01 | 2012-01-01 00:00:00
  1 | 2012-01-01 00:00:00+01 | 2012-01-01 00:00:00

此解决方案的棘手部分可能是输入本地时间戳。只要在本地输入所有数据,这很容易。但是,如果你输入洛杉矶纽约的数据,就需要考虑。请使用AT TIME ZONE construct

SELECT ('2012-1-1 00:00+00' AT TIME ZONE 'America/New_York')::timestamp
     , ('2012-1-1 00:00+00' AT TIME ZONE 'America/Los_Angeles')::timestamp

      timezone       |      timezone
---------------------+---------------------
 2011-12-31 19:00:00 | 2011-12-31 16:00:00

请注意我如何使用带时区的时间戳作为输入。对于带或不带时区的时间戳,AT TIME ZONE会给出不同的结果。

答案 1 :(得分:0)

我猜您可以将日期存储为字符串并使用ISO 8601或RFC 2822,因此您还可以存储时区。 或者实际上,对于更多比较选项,将时间戳和时区存储在2个不同的列中。