67

Postgresから日付を正しく選択する際に問題が発生します-日付はUTCに保存されていますが、Date()関数で正しく変換されていません。

タイムスタンプを日付に変換すると、太平洋標準時の午後4時を過ぎている場合に間違った日付が表示されます。

2012-06-212012-06-20この場合にあるはずです。

starts_at列のデータ型はtimestamp without time zoneです。これが私の質問です:

PSTタイムゾーンに変換せずに:

Select starts_at from schedules where id = 40;

      starts_at      
---------------------
 2012-06-21 01:00:00

変換すると次のようになります。

Select (starts_at at time zone 'pst') from schedules where id = 40;
        timezone        
------------------------
 2012-06-21 02:00:00-07

ただし、どちらもタイムゾーンの正しい日付に変換されません。

4

4 に答える 4

65

基本的にあなたが望むものは次のとおりです。

$ select starts_at AT TIME ZONE 'UTC' AT TIME ZONE 'US/Pacific' from schedules where id = 40

私はこの記事から解決策を得ました、それはまっすぐな金です!!! この重要な問題を非常に明確に説明しています。pstgrsqlTZ管理をよりよく理解したい場合は、読んでください。

現地時間でゾーンなしでPostgreSQLタイムスタンプを表現する

これが起こっていることです。まず、PSTタイムゾーンがUTCタイムゾーンより8時間遅れていることを知っておく必要があります。たとえば、2014年1月1日午後4時30分PST(2014年1月1日水曜日16:00:30 -0800)は、2014年1月2日00:30に相当します。協定世界時(2014年1月2日木曜日00:00:30 +0000)。PSTの午後4時以降はいつでも、UTCとして解釈されて翌日にスリップします。

また、前述のErwin Brandstetterのように、postresqlには2種類のタイムスタンプデータ型があります。1つはタイムゾーンあり、もう1つはタイムゾーンなしです。タイムスタンプにタイムゾーンが含まれている場合は、次のようにします。

$ select starts_at AT TIME ZONE 'US/Pacific' from schedules where id = 40

動作します。ただし、タイムスタンプがタイムゾーンなしの場合、上記のコマンドの実行は機能しません。最初にタイムゾーンなしのタイムスタンプをタイムゾーン付きのタイムスタンプ、つまりUTCタイムゾーンに変換してから、目的の「PST」または「US/」に変換する必要があります。パシフィック」(これは、夏時間の問題までは同じです。どちらでも問題ないと思います)。

タイムゾーンのないタイムスタンプを作成する例を示してみましょう。便宜上、ローカルタイムゾーンが実際に「PST」であると仮定しましょう(そうでない場合は、少し複雑になりますが、この説明では不要です)。

私が持っていると言う:

$ select timestamp '2014-01-2 00:30:00' AS a, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AS b,  timestamp '2014-01-2 00:30:00' AT TIME ZONE 'UTC' AT TIME ZONE 'PST' AS c, timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

これにより、次のようになります。

"a"=>"2014-01-02 00:30:00"   (This is the timezoneless timestamp)
"b"=>"2014-01-02 00:30:00+00" (This is the UTC TZ timestamp, note that up to a timezone, it is equivalent to the timezoneless one)
"c"=>"2014-01-01 16:30:00" (This is the correct 'PST' TZ conversion of the UTC timezone, if you read the documentation postgresql will not print the actual TZ for this conversion)
"d"=>"2014-01-02 08:30:00+00"

最後のタイムスタンプは、postgresqlでタイムゾーンのないタイムスタンプをUTCから「PST」に変換することに関するすべての混乱の理由です。私たちが書くとき:

timestamp '2014-01-2 00:30:00' AT TIME ZONE 'PST' AS d

タイムゾーンのないタイムスタンプを取得して、それを'PST TZに変換しようとしています(postgresqlはUTC TZからタイムスタンプを変換することを間接的に理解していると想定していますが、postresqlには独自の計画があります!)。実際には、postgresqlが行うことは、タイムゾーンのないタイムスタンプ( '2014-01-2 00:30:00)を取り、それがすでに' PST' TZタイムスタンプ(つまり、2014-01-2 00:30)であるかのように扱うことです。 :00 -0800)そしてそれをUTCタイムゾーンに変換します!!! つまり、実際には、後ろではなく8時間前にプッシュします。したがって、(2014-01-02 08:30:00 + 00)が得られます。

とにかく、この最後の(直感的でない)行動はすべての混乱の原因です。より詳細な説明が必要な場合は、記事を読んでください。実際には、この最後の部分とは少し異なる結果が得られましたが、一般的な考え方は同じです。

于 2014-11-18T00:21:01.390 に答える
50

あなたの質問には正確なタイプがわかりません。starts_atあなたは本当にこの情報を含めるべきです、それは解決策への鍵です。推測する必要があります。

PostgreSQLは常にタイプのUTC時間をtimestamp with time zone内部に保存します。timezone入力と出力(表示)は、現在の設定または指定されたタイムゾーンに調整されます。の効果AT TIME ZONEも、基になるデータ型によって異なります。見る:

dateタイプからを抽出するtimestamp [without time zone]と、現在のタイムゾーンの日付が取得されます。出力の日は、値の表示と同じになりtimestampます。

dateタイプtimestamp with time zonetimestamptz略して)からを抽出する場合、タイムゾーンオフセットが最初に「適用」されます。タイムスタンプの表示と一致する現在のタイムゾーンの日付を引き続き取得します。同じ時点は、ヨーロッパの一部では翌日、たとえばカリフォルニアでは午後4時を過ぎたときに変換されます。特定のタイムゾーンの日付を取得するには、AT TIME ZONE最初に適用します。

したがって、質問の冒頭で説明する内容は、例と矛盾します。

それstarts_atがatimestamp [without time zone]であり、サーバーの時刻が現地時間に設定されているとします。テスト:

SELECT now();

それはあなたの壁の時計と同じ時刻を表示しますか?はいの場合(そしてdbサーバーが正しい時刻で実行されている場合)、timezone現在のセッションの設定はローカルタイムゾーンと一致します。timezoneいいえの場合は、セッションのためにあなたpostgresql.confまたはあなたのクライアントの設定にアクセスすることをお勧めします。マニュアルの詳細。

オフセットは、タイムスタンプリテラルに表示されるものtimezoneと反対の符号を使用していることに注意してください。見る:

starts_atちょうどからあなたのローカル日付を取得するには

SELECT starts_at::date

に等しい:

SELECT date(starts_at)

ところで、あなたの現地時間は現在UTC-8ではなくUTC-7です。これは、夏時間が有効になっているためです(人類の明るい考えの中にはありません)。

太平洋標準時(PST)は、通常、UTC(協定世界時)よりも8時間「早い」(大きいtimestamp値)ですが、夏時間(現在など)の間は7時間になる場合があります。そのため、例のようにtimestamptz表示さ2012-06-21 02:00:00-07れます。構成AT TIME ZONE 'PST'は夏時間を考慮に入れます。これらの2つの式は、異なる結果(1つは冬、もう1つは夏)を生成し、キャスト時に異なる日付になる可能性があります。

SELECT '2012-06-21 01:00:00'::timestamp AT TIME ZONE 'PST'
     , '2012-12-21 01:00:00'::timestamp AT TIME ZONE 'PST'
于 2012-06-22T00:02:39.163 に答える
11

これは古いものですが、PST / PDTの問題を回避するために、キャスト時にATTIMEZONE「US/Pacific」の使用を検討することをお勧めします。それで

SELECT starts_at::TIMESTAMPTZ AT TIME ZONE "US/Pacific" 
  FROM schedules 
 WHERE ID = '40';
于 2014-08-04T16:43:33.067 に答える
-1
cast(master.Stamp5DateTime as date) >= '05-05-2019' AND 

cast(master.Stamp5DateTime as date) <= '05-05-2019' 
于 2019-06-07T09:35:51.817 に答える