是的,PostgreSQL在内部存储所有时间戳为UTC。对于timestamp with time zone
,时区偏移量仅适用于将时间调整为UTC,但不会显式存储。
我不会存储时区字符串或更少的时区缩写(这些不是精确的)。这可能稍后需要昂贵的计算,因为你必须考虑夏令时和国际时间制度的其他古怪。
您可以存储时区间隔偏移量(需要12字节)或秒的数值量(需要4个字节作为整数)等我在此related answer演示。
或者像你已经提出的那样:除了UTC时间戳之外还存储本地时间戳(需要8字节)。这会让你的任务变得轻松。请看下面的演示::
-- 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
为带时区或不带时区的时间戳提供了不同的结果。
作为字符串存储日期/时间是一种非常肮脏的处事方式,应该避免 – Skuld 2012-02-07 16:29:09
数据库中的日期/时间字段是不是一个字符串? 我同意你的查询比较,但如果不需要将它存储为ISO 8601字符串不应该是一个问题 – 2012-02-08 17:29:27
除非postgresql做与其他数据库引擎非常不同的东西,否则,datetime永远不会存储为字符串(通常它是表示从过去的特定日期/时间定义的时间量的整数值) – Skuld 2012-02-10 16:43:53