PostgreSQLから現在のUNIXタイムスタンプを取得するにはどうすればよいですか?


91

Unixタイムスタンプは、UTC 1970年1月1日午前0時からの秒数です。

PostgreSQLから正しいUNIXタイムスタンプを取得するにはどうすればよいですか?

currenttimestamp.comおよびtimestamp.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

回答:


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時にリリースされる場合があります。

単一のタイムゾーンでのみ作業する場合は、(mis)usingで逃げることができますtimestamptimestamptzDSTに対応するための変換は十分に賢く、タイムスタンプは変換のために現在のタイムゾーンにあると想定されます。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はタイムゾーンの指示を黙って無視します


結果の小数を小数点なしの整数に変換する方法は何でも構いません(数値と小数を1つの大きな整数としてマージすることを意味します)。ありがとう。
WM

このようにしかしあなたは本当にそれをしたくないと確信しています。おそらく、10の累乗で乗算し、残りの小数を削除したいでしょうか?
ジャックダグラス

2
@WMこんな感じかな?SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23

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

postgresタイムゾーン変換は結果からタイムゾーン情報を破棄するため、正しいタイムスタンプを返しません:

9.9.3。タイムゾーンで

構文:タイムゾーンなしのタイムスタンプAT TIME ZONEゾーン
戻り値:タイムゾーン付きのタイムスタンプ
指定されたタイムゾーンにあるタイムゾーンなしの特定のタイムスタンプを扱います

構文:タイムゾーン付きタイムスタンプAT TIME ZONEゾーン
戻り値:タイムゾーンなしタイムスタンプタイムゾーン
指定のタイムスタンプを、タイムゾーン指定なしで新しいタイムゾーンに変換します。

その後、extractはタイムゾーンのないタイムスタンプを調べ、ローカルタイムであると見なします(実際には既に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変換を実行し、2行目は結果に新しいタイムゾーンを割り当てます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.