2

我认为 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 小时的差异支持这一点。

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

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

这又不支持该谓词。

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

4

1 回答 1

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 zone并且local timestamp with time zone没有意义,因为您总是可以得到utc

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

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

问:您是说如果我的时区设置为会话中的本地时间,那么我应该在本地看到例如 ...14:00:00+02 的 utc 值为 ...12:00:00

是的。

问:当从我的应用程序向本地字段写入内容时,在那里设置哪个时区很重要?

确切地。

问:如何在 JDBS-session 中设置这个?

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

 SET timezone='Europe/Berlin';

通常它是从环境中自动设置的,但可以在各个级别强制设置,包括postgresql.conf. 在会话中显式设置它将覆盖其他任何内容。

问:我能否以某种方式查看时间戳的原始值,以确保它不仅仅是显示时的表示问题

除了在较低级别运行的pageinspect之外,我不知道如何做到这一点。

于 2013-06-27T12:44:01.807 回答