web-dev-qa-db-ja.com

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

NIXタイムスタンプ は、1970年1月1日のUTC午前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
99
Jonas

Postgresでは、_timestamp with time zone_はtimestamptz、_timestamp without time zone_はtimestampと省略できます。簡単にするために、短い型名を使用します。

あなたが言うように、postgres timestamptzのようなUnixタイムスタンプをnow()から取得するのは簡単です:

_select extract(Epoch from now());
_

now()を含む、timestamptz型の絶対時刻を取得するために知っておく必要があるのは、これだけです。

timestampフィールドがある場合にのみ、状況は複雑になります。

now()のようなtimestamptzデータをそのフィールドに入れると、最初に特定のタイムゾーンに変換されます(明示的に_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はタイムゾーンの指示を黙って無視します。

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

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

9.9.3。 ATタイムゾーン

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

構文:タイムゾーン付きのタイムスタンプAT TIME ZONE 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番目は結果に新しいタイムゾーンを割り当てます。

23
axil