web-dev-qa-db-ja.com

PostgreSQLのタイムゾーンの有無によるタイムスタンプの違い

データ型がWITH TIME ZONEWITHOUT TIME ZONEの場合、タイムスタンプ値はPostgreSQLで異なる方法で保存されますか?簡単なテストケースで違いを説明できますか?

149
Larsenal

違いは 日付/時刻型のPostgreSQLドキュメント で説明されています。はい、TIMEまたはTIMESTAMPの処理は、1つのWITH TIME ZONEまたはWITHOUT 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)
124
bignose

参照されているPostgreSQLドキュメントよりも理解しやすいように説明しようとします。

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

  • TIMESTAMP WITHOUT TIME ZONElocal date-time(壁掛けカレンダーの日付と壁時計の時刻)を保存します。 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 ZONEは、UTCタイムラインのポイントを格納します。見た目(時間、分など)はタイムゾーンによって異なりますが、常に同じ「物理的な」瞬間(実際の物理的な出来事の瞬間など)を指します。入力は内部的に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.OffsetDateTime(またはもちろんJava.util.DateまたはJava.sql.Timestamp)にマッピングすることになっています。

両方のTIMESTAMPバリエーションがUTC日時を保存すると言う人もいます。種類ですが、私の意見では、そのように言えば混乱しています。 TIMESTAMP WITHOUT TIME ZONETIMESTAMP WITH TIME ZONEのように保存され、ローカルタイムと同じ年、月、日、時間、分、秒、マイクロ秒をUTCタイムゾーンでレンダリングします。しかし、UTCの解釈が示すタイムライン上のポイントを表すことを意図したものではなく、ローカルの日付/時刻フィールドがエンコードされる方法にすぎません。 (実際のタイムゾーンはUTCではないため、タイムライン上のドットのクラスターです。それが何であるかはわかりません。)

17
ddekany

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

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
9
serby