如何从PostgreSQL获取当前的unix时间戳?


91

Unix时间戳是自1970年1月1日UTC午夜以来的秒数。

如何从PostgreSQL获取正确的Unix时间戳?

currenttimestamp.comtimestamp.1e5b.de进行比较时,我没有从PostgreSQL获得预期的时间:

这将返回正确的时间戳:

SELECT extract(epoch from now());

虽然这不是:

SELECT extract(epoch from now() at time zone 'utc');

我住在时区UTC +02。从PostgreSQL获取当前unix时间戳的正确方法是什么?

这将返回正确的时间和时区:

SELECT now();
              now
-------------------------------
 2011-05-18 10:34:10.820464+02

另一个比较:

select now(), 
extract(epoch from now()), 
extract(epoch from now() at time zone 'utc');
              now              |    date_part     |    date_part
-------------------------------+------------------+------------------
 2011-05-18 10:38:16.439332+02 | 1305707896.43933 | 1305700696.43933
(1 row)

Unix timestamp from the web sites:
1305707967

Answers:


82

Postgres里,timestamp with time zone可简写为timestamptz,和timestamp without time zone作为timestamp。为了简单起见,我将使用较短的类型名称。

正如您所说,从timestamptz类似的postgres获取Unix时间戳now()很简单:

select extract(epoch from now());

这实际上是您从任何类型timestamptz(包括)获得绝对时间所需的全部知识now()

只有拥有一个timestamp领域,事情才会变得复杂。

当您将timestamptz类似数据now()放入该字段时,它将首先转换为特定时区(显式at time zone转换为会话时区或通过转换为会话时区),并且时区信息将被丢弃。它不再是指绝对时间。这就是为什么您通常不希望像timestamp往常一样存储时间戳的原因timestamptz-也许电影是在每个时区的特定日期的晚上6点发布的,这就是用例。

如果您只在一个时区工作,则可能会误用timestamp。转换回timestamptz足够聪明,可以应付DST,并且出于转换目的,时间戳记假定在当前时区中。这是GMT / BST的示例:

select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
     , '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;

/*
|timestamptz           |timestamptz           |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/

DBFiddle

但是,请注意以下令人困惑的行为:

set timezone to 0;

values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
    , (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);

/*
|column1|column2               |
|------:|:---------------------|
|      1|1970-01-01 00:00:00+00|
|      2|1970-01-01 00:00:00+00|
*/

DBFiddle

是因为

PostgreSQL在确定文字字符串的类型之前从未检查过文字字符串的内容,因此会将[…]都视为没有时区的时间戳。为了确保将文字视为带时区的时间戳,请为其提供正确的显式类型……在已确定为没有时区的时间戳的文字中,PostgreSQL将默默地忽略任何时区指示


任何想法如何将所得的十进制转换为不带小数点的整数(我的意思是将数字和十进制合并为一个大整数)。谢谢。
WM

这样,但我敢肯定您真的不想这样做。也许您想乘以10的幂并去除任何剩余的小数?
杰克·道格拉斯

2
@WM可能是这样吗?SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
乔23

21
SELECT extract(epoch from now() at time zone 'utc');

不会返回正确的时间戳,因为postgres时区转换会从结果中丢弃时区信息:

9.9.3。时区

语法:不带时区的时间戳AT TIME ZONE区域
返回:带时区的时间戳
将给定的不带时区的时间戳视为位于指定时区中

语法:带时区的时间戳记AT TIME ZONE区域
返回:不带时区的
时间戳记将具有时区的给定时间戳转换为新的时区,而不指定时区

之后,提取会查看没有时区的时间戳,并认为它是本地时间(尽管实际上已经是utc)。

正确的方法是:

select now(),
       extract(epoch from now()),                                          -- correct
       extract(epoch from now() at time zone 'utc'),                       -- incorrect
       extract(epoch from now() at time zone 'utc' at time zone 'utc');    -- correct

          now                  |    date_part     |    date_part     |    date_part
-------------------------------+------------------+------------------+------------------
 2014-10-14 10:19:23.726908+02 | 1413274763.72691 | 1413267563.72691 | 1413274763.72691
(1 row)

在最后一行中,第一行at time zone执行转换,第二行为结果分配新的时区。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.