データ型timestamp
はの短縮名ですtimestamp without time zone
。
他のオプションtimestamptz
はの略ですtimestamp with time zone
。
timestamptz
ある好適な、文字通り、日付/時間ファミリのタイプ。にtypispreferred
設定されておりpg_type
、関連性があります。
内部的には、タイムスタンプはディスクおよびRAMの8バイトのストレージを占有します。これは、Postgresエポック、2000-01-01 00:00:00 UTCからのマイクロ秒数を表す整数値です。
Postgresは、UNIXエポック(1970-01-01 00:00:00 UTC)から一般的に使用されるUNIX時間カウント秒の組み込みの知識を持ち、関数to_timestamp(double precision)
またはでそれを使用しますEXTRACT(EPOCH FROM timestamptz)
。
ソースコード:
*タイムスタンプと間隔のh / m / sフィールドは、
*マイクロ秒単位のint64値。(かつて彼らは
*秒単位の倍精度値。)
そして:
/ * UnixおよびPostgresでの0日目と同等のユリウス日付* /
#define UNIX_EPOCH_JDATE 2440588 / * == date2j(1970、1、1)* /
#define POSTGRES_EPOCH_JDATE 2451545 / * == date2j(2000、1、1)* /
マイクロ秒の解像度は、秒の最大6の小数桁に変換されます。
timestamp
として入力された値は、タイムゾーンが明示的に提供されていないことをPostgresに伝えます。現在のタイムゾーンが想定されます。Postgres は誤って追加されたタイムゾーン修飾子を無視します!timestamp
[without time zone]
表示のためにシフトされる時間はありません。同じタイムゾーン設定ですべて問題ありません。別のタイムゾーン設定では意味が変わりますが、値と表示は同じままです。
timestamptz
取り扱いtimestamp with time zone
が微妙に異なります。私はここにマニュアルを引用します:
の場合timestamp with time zone
、内部的に保存される値は常にUTC(協定世界時...)です。
大胆な強調鉱山。タイムゾーン自体は保存されることはありません。これは、保存されているUTCタイムスタンプを計算するために使用される入力修飾子です。または、表示するローカル時間を計算するために使用される出力修飾子です。タイムゾーンオフセットが追加されています。timestamptz
入力時にオフセットを追加しない場合、セッションの現在のタイムゾーン設定が想定されます。すべての計算はUTCタイムスタンプ値で行われます。複数のタイムゾーンを処理する必要がある(または処理する必要がある場合)は、を使用しますtimestamptz
。
psqlやpgAdminなどのクライアント、またはlibpqを介して通信するすべてのアプリケーション(pg gemを使用したRubyなど)には、現在のタイムゾーンのタイムスタンプとオフセットが、または要求されたタイムゾーンに従って表示されます(以下を参照)。常に同じ時点であり、表示形式のみが異なります。または、マニュアルにあるように:
すべてのタイムゾーン対応の日付と時刻は、内部でUTCに格納されます。これらは
、クライアントに表示される前に、TimeZone構成パラメーターで指定されたゾーンの現地時間に変換されます。
次の簡単な例(psql)を考えてみます。
db =#SELECT timestamptz '2012-03-05 20:00 +03 ';
タイムスタンプ
------------------------
2012-03-05 18:00:00 +01
大胆な強調鉱山。ここで何が起こったのですか?入力リテラルに
任意のタイムゾーンオフセットを選択しました+3
。Postgresにとって、これはUTCタイムスタンプを入力する多くの方法の1つにすぎません2012-03-05 17:00:00
。クエリの結果がされて表示された設定を現在のタイムゾーンのためのウィーン/オーストリアを相殺している私のテストでは、+1
冬の間および+2
:夏の期間中に2012-03-05 18:00:00+01
、それは冬時間に落ちるので。
Postgresは、この値の入力方法をすでに忘れています。覚えているのは、値とデータ型だけです。10進数と同じように。numeric '003.4'
、numeric '3.40'
またはnumeric '+3.4'
-すべての結果はまったく同じ内部値になります。
AT TIME ZONE
このロジックを理解するとすぐに、好きなことができます。現在欠けているのは、特定のタイムゾーンに従ってタイムスタンプリテラルを解釈または表現するためのツールです。これがAT TIME ZONE
構造の出番です。2つの異なるユースケースがあります。timestamptz
に変換されtimestamp
、その逆も同様です。
UTCに入るにはtimestamptz
2012-03-05 17:00:00+0
:
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC'
...これは次と同等です:
SELECT timestamptz '2012-03-05 17:00:00 UTC'
EST timestamp
(東部標準時)と同じ時点を表示するには:
SELECT timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC' AT TIME ZONE 'EST'
そうです、AT TIME ZONE 'UTC'
2回。最初のものは、timestamp
値を(指定された)UTCタイムスタンプとして解釈し、タイプを返しtimestamptz
ます。もう一つは変換timestamptz
にtimestamp
時間内に、このユニークな点のタイムゾーンESTディスプレイのどの時計-指定されたタイムゾーンの「EST」。
例
SELECT ts AT TIME ZONE 'UTC'
FROM (
VALUES
(1, timestamptz '2012-03-05 17:00:00+0')
, (2, timestamptz '2012-03-05 18:00:00+1')
, (3, timestamptz '2012-03-05 17:00:00 UTC')
, (4, timestamp '2012-03-05 11:00:00' AT TIME ZONE '+6')
, (5, timestamp '2012-03-05 17:00:00' AT TIME ZONE 'UTC')
, (6, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'US/Hawaii') -- ①
, (7, timestamptz '2012-03-05 07:00:00 US/Hawaii') -- ①
, (8, timestamp '2012-03-05 07:00:00' AT TIME ZONE 'HST') -- ①
, (9, timestamp '2012-03-05 18:00:00+1') -- ② loaded footgun!
) t(id, ts);
同じUTCタイムスタンプを保持するtimestamptz列を持つ8(または9)の同一の行を返します2012-03-05 17:00:00
。9行目は私のタイムゾーンで動作しますが、邪悪な罠です。下記参照。
① ハワイ時間のタイムゾーン名とタイムゾーンの省略形を含む行6〜8はDST(夏時間)の対象であり、現在ではありませんが異なる場合があります。のようなタイムゾーン名'US/Hawaii'
は、DSTルールとすべての履歴シフトを自動的に認識しますが、のような略語HST
は、固定オフセットの単なるダムコードです。夏時間/標準時間には別の略語を追加する必要がある場合があります。名前は正しく解釈する任意の与えられた時間帯にタイムスタンプを。略語は安いですが、与えられたタイムスタンプのために正しいものである必要があります:
夏時間は、人類がこれまで考え出した最も明るいアイデアの1つではありません。
② ロードされたフットガンとしてマークされた列9 は私にとっては機能しますが、偶然にのみ機能します。リテラルをに明示的にキャストした場合timestamp [without time zone]
、タイムゾーンオフセットは無視されます。ベアタイムスタンプのみが使用されます。このtimestamptz
例では、値は列のタイプと一致するように自動的に強制されます。このステップでtimezone
は、現在のセッションの設定が想定されます。これは、たまたま+1
私の場合(ヨーロッパ/ウィーン)と同じタイムゾーンです。しかし、おそらくあなたの場合はそうではありません-これは異なる値になります。つまり、timestamptz
リテラルをキャストしないでください。キャストするとtimestamp
、タイムゾーンオフセットが失われます。
あなたの質問
ユーザーは時間を保存します。たとえば、2012年3月17日午後7時です。タイムゾーン変換やタイムゾーンを保存したくありません。
タイムゾーン自体は保存されません。上記のいずれかの方法を使用して、UTCタイムスタンプを入力します。
ユーザーが指定したタイムゾーンのみを使用して、ユーザーのローカルタイムゾーンの現在時刻の「前」または「後」のレコードを取得します。
異なるタイムゾーンのすべてのクライアントに対して1つのクエリを使用できます。
絶対世界時間の場合:
SELECT * FROM tbl WHERE time_col > (now() AT TIME ZONE 'UTC')::time
ローカルクロックによる時間の場合:
SELECT * FROM tbl WHERE time_col > now()::time
まだ背景情報に飽きていませんか?マニュアルにもっとあります。