PostgreSQLのタイムゾーンあり/なしのタイムスタンプの違い


回答:


157

違いは、日付/時刻型のPostgreSQLドキュメントで説明されています。はい、の治療TIMEまたはTIMESTAMP1との間で異なりますWITH TIME ZONEWITHOUT TIME ZONE。値の保存方法には影響しません。それらの解釈方法に影響します。

これらのデータ型に対するタイムゾーンの影響については、特にドキュメントで説明されています。違いは、システムが値について合理的に知ることができるものから生じます。

  • 値の一部としてタイムゾーンを使用すると、値をクライアントでローカル時間としてレンダリングできます。

  • 値の一部としてタイムゾーンがない場合、明らかにデフォルトのタイムゾーンはUTCであるため、そのタイムゾーンでレンダリングされます。

動作は、少なくとも3つの要因によって異なります。

  • クライアントのタイムゾーン設定。
  • 値のデータ型(つまりWITH TIME ZONEまたはWITHOUT TIME ZONE)。
  • 値が特定のタイムゾーンで指定されているかどうか。

これらの要因の組み合わせをカバーする例を次に示します。

foo=> SET TIMEZONE TO 'Japan';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
      timestamp      
---------------------
 2011-01-01 00:00:00
(1 row)

foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
      timestamptz       
------------------------
 2011-01-01 00:00:00+09
(1 row)

foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
      timestamp      
---------------------
 2011-01-01 00:00:00
(1 row)

foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
      timestamptz       
------------------------
 2011-01-01 06:00:00+09
(1 row)

foo=> SET TIMEZONE TO 'Australia/Melbourne';
SET
foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP;
      timestamp      
---------------------
 2011-01-01 00:00:00
(1 row)

foo=> SELECT '2011-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE;
      timestamptz       
------------------------
 2011-01-01 00:00:00+11
(1 row)

foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP;
      timestamp      
---------------------
 2011-01-01 00:00:00
(1 row)

foo=> SELECT '2011-01-01 00:00:00+03'::TIMESTAMP WITH TIME ZONE;
      timestamptz       
------------------------
 2011-01-01 08:00:00+11
(1 row)

88
値の挿入/取得プロセスを参照する場合にのみ修正してください。しかし、読者は、両方のデータ・タイプということを理解すべきである、timestamp with time zonetimestamp without time zone、Postgresのではない*ない実際のタイムゾーン情報を格納します。これは、データタイプのドキュメントページで一目で確認できます。どちらのタイプも同じ数のオクテットを使用し、値の保存範囲があるため、タイムゾーン情報を保存するスペースがありません。ページのテキストはこれを確認します。誤解の一部:「tzなし」は「データ挿入時にオフセットを無視する」を意味し、「tz付き」は「オフセットを使用してUTCに調整する」ことを意味します。
バジルブルク14

42
データタイプは、2つ目の誤解です。「タイムゾーン」と言いますが、実際にはUTC / GMTからのオフセットについて話しています。タイムゾーンは、実際にはオフセット、夏時間(DST)およびその他の異常に関するルール/履歴です。
バジルブルク14

4
オフセットとは、タイムゾーンとDSTの規則のことです。オフセットを指定するとタイムゾーンを検出できませんが、タイムゾーンとDSTルールを指定するとオフセットを検出できます。
igorsantos07 2015年

3
公式ドキュメントの引用:すべてのタイムゾーン対応の日付と時刻は、内部でUTCに格納されています。これらは、クライアントに表示される前に、TimeZone構成パラメーターで指定されたゾーンの現地時間に変換されます。
Guillaume Husta 2017

2
@ igorsantos07タイムゾーン、DSTの変更およびその他の変更に関する一連のルール/履歴です。あなたの言い回しは不必要に思えます。そして、「オフセットはタイムゾーンとDSTの規則である」というあなたの発言は単に間違っています。オフセットは、時間、分、秒の数にすぎません。
バジルブルク

34

参照しているPostgreSQLのドキュメントよりもわかりやすく説明するようにしています。

どちらのTIMESTAMPバリアントも、名前が示すとおり、タイムゾーン(またはオフセット)を保存しません。違いは、格納形式自体ではなく、格納されたデータの解釈(および目的のアプリケーション)にあります。

  • TIMESTAMP WITHOUT TIME ZONEローカルの日付時刻(別名、壁掛けカレンダーの日付と壁掛け時計の時刻)を格納します。PostgreSQLが認識できる限り、そのタイムゾーンは指定されていません(アプリケーションがそれを知っている場合もあります)。したがって、PostgreSQLは入力または出力でタイムゾーン関連の変換を行いません。値がとしてデータベースに入力された場合、'2011-07-01 06:30:30'後で表示するタイムゾーンには何も表示されず、2011年、07日、01日、06時間、30分、30秒(ある形式)と表示されます。また、任意のオフセットまたはあなたが入力で指定した時間帯は、PostgreSQLによって無視され、そう'2011-07-01 06:30:30+00''2011-07-01 06:30:30+05'ばかり同じです'2011-07-01 06:30:30'。Java開発者の場合:に似ていjava.time.LocalDateTimeます。

  • TIMESTAMP WITH TIME ZONEUTCタイムライン上のポイントを保存します。見た目(時間、分など)はタイムゾーンによって異なりますが、常に同じ「物理的な」瞬間(実際の物理的なイベントの瞬間など)を指します。入力は内部でUTCに変換され、それが格納されます。そのため、入力のオフセットは既知である必要があるため、入力に明示的なオフセットまたはタイムゾーン(など'2011-07-01 06:30:30')が含まれていない場合、PostgreSQLセッションの現在のタイムゾーンであると想定されます。それ以外の場合、明示的に指定されたオフセットまたはタイムゾーンが使用されます。 (のように'2011-07-01 06:30:30+05')。出力は、PostgreSQLセッションの現在のタイムゾーンに変換されて表示されます。Java開発者の場合:これはjava.time.Instant(解像度は低くなりますが)に似ていますが、JDBCおよびJPA 2.2では、それをjava.time.OffsetDateTimejava.util.Dateまたはjava.sql.Timestamp もちろん)。

両方のTIMESTAMPバリエーションがUTC日時を格納すると言う人もいます。ちょっと、でも私の意見ではそのように言うのは紛らわしいです。TIMESTAMP WITHOUT TIME ZONEはのように格納さTIMESTAMP WITH TIME ZONEれ、UTCタイムゾーンでレンダリングされ、たまたまローカルの日付時刻と同じ年、月、日、時間、分、秒、マイクロ秒が与えられます。しかし、それはUTC解釈が言うタイムライン上のポイントを表すことを意味するのではなく、それはローカルの日時フィールドがエンコードされる方法にすぎません。(リアルタイムゾーンはUTCではないため、タイムライン上のドットのクラスターです。それが何であるかはわかりません。)


TIMESTAMP WITH TIME ZONEとして取得しても問題はありませんInstant。どちらもUTCのタイムライン上のポイントを表します。より自己文書化されているためInstant、私の意見では、OffsetDateTimeA が優先されTIMESTAMP WITH TIME ZONEます。A は常にデータベースからUTCとして取得され、Instantは常にUTCであるため自然な一致ですが、OffsetDateTimeは他のオフセットを運ぶことができます。
バジルブルク2018年

@BasilBourque残念ながら、現在のJDBC仕様、JPA 2.2仕様、およびPostgreSQL JDBCドキュメントではOffsetDateTime、マッピングされたJava型としてのみ言及しています。Instanceまだどこかで非公式にサポートされているかどうかはわかりません。
ddekany 2018年

質問、あなたは任意のは、私のような入力に指定したオフセット言う'2011-07-01 06:30:30+00''2011-07-01 06:30:30+05' 無視されますが、私はやることができるよinsert into test_table (date) values ('2018-03-24T00:00:00-05:00'::timestamptz);、それは正しくUTCに変換します。ここで、日付はタイムゾーンなしのタイムスタンプです。タイムゾーン付きのタイムスタンプの主な値が何であるかを理解しようとしていますが、問題があります。
pk1m 2018年

@ pk1mあなたは問題を複雑にし::timestamptzます。これで、文字列をTIMESTAMP WITH TIME ZONEに変換しWITHOUT TIME ZONE、さらにに変換すると、セッションタイムゾーン(UTC)から見た、その瞬間の「ウォールカレンダー」の日とウォールクロック時間が格納されます。それでも、オフセットが指定されていないローカルタイムスタンプのみになります(ゾーンなし)。
ddekany

私はpythonを使用していますが、タイムスタンプ対応のdatettimeオブジェクトを挿入すると挿入されます。タイムゾーンでタイムスタンプを使用することに価値があるように思えますが、タイムゾーンを処理する必要はありません。
pk1m 2018年

12

これは役立つはずの例です。タイムゾーンを持つタイムスタンプがある場合、そのタイムスタンプを他のタイムゾーンに変換できます。基本のタイムゾーンがない場合、正しく変換されません。

SELECT now(),
   now()::timestamp,
   now() AT TIME ZONE 'CST',
   now()::timestamp AT TIME ZONE 'CST'

出力:

-[ RECORD 1 ]---------------------------
now      | 2018-09-15 17:01:36.399357+03
now      | 2018-09-15 17:01:36.399357
timezone | 2018-09-15 08:01:36.399357
timezone | 2018-09-16 02:01:36.399357+03

5
「正しく変換されない」という文言は真実ではありません。あなたは何timestamptimestamptz意味し、理解する必要があります。timestamptz絶対時刻(UTC)をtimestamp意味しますが、特定のタイムゾーンで時計が何を示したかを示します。したがって、timestamptzタイムゾーンに変換するときに、この絶対的な時点でニューヨークの時計が何を示していたのでしょうか。一方、を「変換」するとき、ニューヨークの時計がxを示した絶対的な時点は何だったのかとtimestamp尋ねています。
フィリップ2016年

AT TIME ZONE構築物は、すでに理解していても、独自のティーザー脳であるWITH対のWITHOUT TIME ZONEタイプを。したがって、それらを説明するための好奇心の強い選択です。(:(タイムスタンプをタイムスタンプに、またはその逆にAT TIME ZONE変換します...正確には明らかではありません。)WITH TIME ZONEWITHOUT TIME ZONE
ddekany

now()::timestamp AT TIME ZONE 'CST'ゾーン 'CST'のクロックが、ローカルクロックが現在表示している時間をいつ表示するかを除いて、意味がありません
Jasen
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.