这应该很简单,但我遇到了一些令人尴尬的麻烦。
在PostgreSQL 9.1中,我需要在数据库中存储一个存储为DATE
的字段,就好像它是TIMESTAMPTZ
表示该日期的午夜UTC一样。我希望以干净和可读的方式做到这一点,有人可以来,看看,并了解正在发生的事情。
到目前为止,我发现这样做的唯一方法都非常难看。一个人将其转换为TIMESTAMP WITHOUT TIME ZONE
,然后通过将其解释为UTC来创建TIMESTAMP WITH TIME ZONE
:
SELECT CAST(DATE '2012-01-01' AS TIMESTAMP WITHOUT TIME ZONE) AT TIME ZONE 'utc'
另一种方式更糟:
('2012-01-01'::date)::timestamptz - (current_timestamp AT TIME ZONE 'UTC' - current_timestamp)
因为它将日期转换为当地时间午夜的时间戳,然后减去时区偏移量。我无法找到任何方法将该偏移作为一个间隔本地(这看起来很疯狂)所以我通过将本地时间的current_timestamp
与UTC中的current_timestamp
进行比较来获得它。
我可以解决的唯一方法是使用extract
获取日期部分并从中组合新的timestamptz
。我甚至不会展示那个,它太丑了。
这两种方法都会感到各种奇怪和错误。是否有任何理智的方式 - 标准或无 - 以可读且易于理解的方式从当天午夜UTC的DATE
转换为timestamptz
?
我正在寻找类似(虚构,不起作用)的东西
'2012-01-01'::date AS TIMESTAMPTZ IN TIME ZONE '00:00';
或
to_timestamp('2012-01-01'::date, '00:00'::time, 'UTC');
请指出我错过的愚蠢明显的事情。
请注意,我正在测试以确保日期在内部真正正确,而不仅仅是显示日期,其中extract(epoch from $1)
$1
是转换日期。
答案 0 :(得分:4)
你的第一种方法是正确的。这不是那么难看,是吗?在简化的Postgres语法中:
SELECT '2012-1-1'::date::timestamp AT TIME ZONE 'UTC';
应用于变量或列,它看起来更优雅:
SELECT mydate::timestamp AT TIME ZONE 'UTC';
如果您要手动输入日期,可以快捷方式:
SELECT '2012-1-1 0:0'::timestamp AT TIME ZONE 'UTC'
结果将始终显示根据客户端的本地时区(即具有相应的偏移量),但这对值没有影响。
答案 1 :(得分:2)
注意:我对PSQL知之甚少,但我对日期/时间问题有一些经验。
你的第一种方式对我来说是正确的。您实际上是从“本地日期”到“本地日期/时间”到“特定时区的日期/时间”。这些都是合理的步骤,我希望在正常的日期/时间API中看到这些步骤。
据我所知,这种方法从未引入系统默认时区,这是一件非常好的事情。它一次执行一个逻辑步骤,假设投射是明智的事情。
您无需担心目标时区中的本地日期/时间不明确或缺失,因为UTC没有任何DST转换。
基本上,它看起来很好。如果它能够正常工作并且表现得很好,我会坚持下去。