Sco*_*007 9 database postgresql timezone timestamp
我们正在讨论在postgres中存储时间戳的最佳方法.目前,所有时间戳都存储为+00,并且我们有与每个客户端关联的时区.我们查找时区并转换发生事件的时间,这会增加复杂性,因为我们需要进行更多连接和更复杂的查询.
另一种方法是连接到Postgres并设置连接的时区,它将所有时间都更改为该时区.
我的问题是在ANZ有4-5个时区.当我们尝试开发票时,我们需要知道某些交易发生的那一天,并且在三个时区之间没有完美的解决方案.
我想在时间戳中包含时区以使其更容易 - TIMESTAMP'1999-01-15 8:00:00 -8:00'
我觉得这是最好的做法,但有些人说这是个坏主意.我们将为ANZ的客户提供准确的发票,最佳解决方案和最优雅的解决方案?
干杯斯科特
leo*_*loy 16
这里没有防弹解决方案.
我的第一个建议:永远不要依赖服务器的默认时区.
我的第二个建议是:选择timestamp- timestamptz根据数据的(主要)语义.
更详细:PostgresSQL有两个时间戳变体,容易混淆命名TIMESTAMP WITHOUT TIMEZONE (timestamp)和TIMESTAMP WITH TIMEZONE (timestamptz).实际上,既不存储时区,也不存储偏移量.两种数据类型占用相同的宽度(4个字节),它们的区别很微妙 - 更糟糕的是,如果你不完全理解它们并且服务器改变了时区,它会咬你.我的理智规则是:
使用TIMESTAMP WITH TIMEZONE (timestamptz)用于存储主要是相关的事件"物理"的时间,为你的主要兴趣在询问是否event 1是之前event 2(不管时区),或计算的时间间隔(以"物理单位",例如,秒;不是"民间"单位为天 - 月等).典型的例子是记录创建/修改时间 - 通常用" Timestamp " 这个词来表示.
使用TIMESTAMP WITHOUT TIMEZONE (timestamp)用于存储该相关信息是事件的"民间时间" (即字段{year-month-day hour-min-sec}作为一个整体),和查询涉及日历计算.在这种情况下,您只会在此处存储"本地时间",即相对于某些未指定(不相关或隐含或存储在其他地方)时区的日期时间.
第二个选项让您更容易查询,例如"在2013-01-20'发生的所有事件"(在每个相应的区域/国家/时区中) - 但是查询"所有事件"更加困难在参考事件之前(物理上)"(除非我们知道它们在同一时区).你选.
如果您需要完整的东西,这两者都不够,您需要将时区或偏移量存储在附加字段中.另一个选项,浪费几个字节,但对查询更有效,是存储两个字段.
另见这个答案.
Luc*_*cas 11
对输入字段使用timestamptz(或timestamp with time zone标准SQL语法),然后可以使用时区或时间偏移为每个插入设置自定义时间偏移,以适合您的偏好.
例…
CREATE TABLE "timetest"
(
"timestamp" timestamptz
);
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 PST');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 Europe/Madrid');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 Europe/Athens');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 GMT+11');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 GMT-11');
INSERT INTO "timetest" ("timestamp") VALUES ('2013-01-01 08:45:00 UTC');
Run Code Online (Sandbox Code Playgroud)
......并且您的时间将相应调整
SELECT * FROM "timetest"; -- note this may default to your timezone
------------------------
[timestamp]
------------------------
2013-01-01 16:45:00+00
2013-01-01 07:45:00+00
2013-01-01 06:45:00+00
2012-12-31 21:45:00+00
2013-01-01 19:45:00+00
2013-01-01 08:45:00+00
2013-01-01 08:45:00+00
Run Code Online (Sandbox Code Playgroud)
或者更好的是,尝试以下......
SELECT
"timestamp" AT TIME ZONE 'Australia/Sydney' AS "Sydney",
"timestamp" AT TIME ZONE 'Australia/Perth' AS "Perth"
FROM "timetest";
--------------------------------------------
[Sydney]..............[Perth]
--------------------------------------------
2013-01-02 03:45:00 - 2013-01-02 00:45:00
2013-01-01 18:45:00 - 2013-01-01 15:45:00
2013-01-01 17:45:00 - 2013-01-01 14:45:00
2013-01-01 08:45:00 - 2013-01-01 05:45:00
2013-01-02 06:45:00 - 2013-01-02 03:45:00
2013-01-01 19:45:00 - 2013-01-01 16:45:00
Run Code Online (Sandbox Code Playgroud)
最后,要了解可用于数据库的时区列表,请尝试:
SELECT * FROM pg_timezone_names ORDER BY utc_offset DESC;
Run Code Online (Sandbox Code Playgroud)