在UTC中存储日期和时间 - 如何在Postgres中进行存储?

23

我正在获取我的数据:日期和时间以协调世界时的格式,分别在csv文件中的不同列中。由于我需要将这个时区转换为我居住的地方的日期和时间(目前是夏令时UTC+2),可能还有其他时区,我在想在涉及数据类型时,将数据插入到postgres数据库中最好的做法是什么。我应该将我的两个数据放在一个单独的列中,还是保持它们作为数据类型的分开,如果不是,我应该使用timestamp或timestampz(或其他什么)。

1个回答

30
使用timestamptz,它将在UTC中存储您的时间戳,并根据客户端的语言环境进行显示。

https://www.postgresql.org/docs/current/static/datatype-datetime.html

对于带有时区的时间戳,内部存储值总是以UTC(协调世界时,传统上称为格林威治标准时间,GMT)表示。具有显式时区的输入值会使用该时区的适当偏移量转换为UTC。如果输入字符串中未指定时区,则假定其在系统的TimeZone参数指示的时区中,并使用时区偏移将其转换为UTC。
输出带有时区的时间戳值时,它总是从UTC转换为当前时区,并以该时区的本地时间显示。要查看另一个时区的时间,请更改时区或使用AT TIME ZONE结构(请参见第9.9.3节)。
还支持单列的另一个好处是,如果您将日期和时间存储在单独的列中,如果要更改日期的时区,则仍然需要将它们组合并转换为时间戳。
不这样做会导致在另一个时区中,日期为'2017-12-31'且时间为'23:01:01'实际上不仅是不同的时间,而且所有的年、月、日都不同。
另一个更新 根据Laurenz的提示,不要忘记以上文档引用的话:“具有显式时区指定的输入值将使用该时区的适当偏移量转换为UTC”。这意味着您必须小心地管理输入日期。例如:
t=# create table t(t timestamptz);
CREATE TABLE
t=# set timezone to 'GMT+5';
SET
t=# insert into t select '2017-01-01 00:00:00';
INSERT 0 1
t=# insert into t select '2017-01-01 00:00:00' at time zone 'UTC';
INSERT 0 1
t=# insert into t select '2017-01-01 00:00:00+02';
INSERT 0 1
t=# select * from t;
           t
------------------------
 2017-01-01 00:00:00-05
 2017-01-01 05:00:00-05
 2016-12-31 17:00:00-05
(3 rows)

同样支持单列的原因是,如果您将日期和时间存储在不同的列中,仍然需要将它们组合并转换为时间戳,如果您想更改日期的时区。例如,2017-06-08 04:00:00 GMT +7是2017-06-07 21:00:00 UTC。 - Łukasz Kamiński
你应该说明如果输入是UTC时间,你要么将TimeZone设置为UTC,要么使用TIMESTAMP '<UTC-string>' AT TIME ZONE UTC - Laurenz Albe
感谢大家! - mycupoftea
客户端是指应用程序的客户端还是直接连接数据库的客户端? - TheRealChx101
1
数据库客户端 - Vao Tsun
@VaoTsun 如果我的时区已经是从 .net core 应用程序的 datetime.UtcNow 中以 UTC 格式表示,并且我将其存储在 timestamptz 列中,那么它应该按原样保存,对吗? - kuldeep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接