PostgreSQL和时间戳的神秘面纱

时间:2013-06-27 07:01:55

标签: postgresql timezone

我认为IT的两个祸害之一是时间戳和时区(另一个是字符编码),其中一个人一次又一次地磕磕绊绊......

在这方面,我目前遇到的问题与存储到PostgreSQL数据库中的Java应用程序中的不同时间戳有关。

为了简单起见,假设有下表:

CREATE TABLE ts_test
(
  id integer NOT NULL,
  utc timestamp without time zone,
  local timestamp with time zone,
  CONSTRAINT pk PRIMARY KEY (id)
)

所以,我必须存储UTC时间戳和本地时间戳,在我的情况下是欧洲中部夏令时,所以目前UTC + 2。

进一步假设表中有2个条目,psql控制台上的输出如下(数据库以UTC格式运行):

# select id,  utc, local, local-utc as diff from ts_test;
 id |         utc         |         local          |   diff   
----+---------------------+------------------------+----------
  1 | 2012-06-27 12:00:00 | 2012-06-27 12:00:00+00 | 00:00:00
  2 | 2012-06-27 12:00:00 | 2012-06-27 14:00:00+00 | 02:00:00
(2 rows)

现在,出现了几个问题:

  • 本地列中的输出究竟是什么意思?
  • 系统如何知道时区,我将值插入?
  • 如何查看存储的真实原始值(例如毫秒)?

我原以为,第一行的本地“12:00:00 + 00”表示它是UTC的12:00,再次是CEST的14:00。但似乎(我的数据库管理员告诉我),第二行的本地“14:00:00 + 00”是14:00 CEST的正确值 - 由2小时的差异支持。 / p>

但是要通过sql insert生成第二行,我必须写

insert into ts_test (id, utc, local) values (2, '2012-06-27 12:00:00', '2012-06-27 16:00:00+02');

再次不支持预测。

所以,总结这个长期的问题 - 任何人都可以告诉我整个事情如何详细运作,输出应该是什么意思以及如何将本地时间戳正确地写入数据库?

1 个答案:

答案 0 :(得分:1)

根据local列的输出,您的SQL会话的时区设置为UTCGMT,而不是您居住的时区。大概这是你的意思是:数据库以UTC格式运行。这是问题的根源,但我们试着详细说明。

db本身作为数据存储库没有时区,但每个SQL会话都有自己的时区。

当SQL会话请求它们时,timestamp without time zone的值会旋转到会话的时区,会显示时间偏移,timestamp with time zone的值将旋转到会话的时区,并显示此时区的时间偏移量。这是两者之间的差异。

时区永远不会存储在任何数据类型中,因为在读取值时,重要的是请求此值的SQL会话的时区。

将您的SQL时区设置为UTC不是一个好主意,因为它与您问题的其他部分相矛盾:

  

所以,我必须存储UTC时间戳和本地时间戳,在我的情况下   是欧洲中部的夏季时间,所以目前UTC + 2

让SQL会话知道您的实时区域,它将按预期开始工作。如果不这样做,timestamp with time zone基本上没用。

另请注意,将同一时间存储在utc timestamp without time zonelocal timestamp with time zone中没有意义,因为您始终可以使用utc获取:

SELECT local AT TIME ZONE 'UTC' FROM ts_test WHERE...

编辑:评论中的问题答案:

  问:你是说如果我的时区设置为当地时间   会话,然后我应该看到例如... 14:00:00 + 02 in local for a   utc值为... 12:00:00

  

问:从我的应用程序写入本地字段时,   重要的是哪个时区?

完全。

  

问:如何在JDBS会话中设置它?

我不知道JDBC,但在SQL级别,例如:

 SET timezone='Europe/Berlin';

通常情况下,它会自动从环境中设置,但可以强制执行各种级别,包括postgresql.conf。在会话中明确设置它将覆盖其他任何内容。

  问:我能否以某种方式看到时间戳的原始值,以确保时间戳   显示

时不仅仅是表示问题

我不知道怎么做,除了pageinspect在较低级别操作。