sql >> データベース >  >> RDS >> PostgreSQL

PostgreSQLデータベースでどのタイムスタンプタイプを選択する必要がありますか?

    まず、PostgreSQLの時間処理と演算は素晴らしく、一般的なケースではオプション3で問題ありません。ただし、これは時間とタイムゾーンの不完全なビューであり、補足することができます:

    1. ユーザーのタイムゾーンの名前をユーザー設定として保存します(例:America/Los_Angeles-0700ではありません 。
    2. ユーザーイベント/時間データを参照フレームのローカルに送信します(-0700などのUTCからのオフセットである可能性があります) 。
    3. アプリケーションで、時間をUTCに変換します TIMESTAMP WITH TIME ZONEを使用して保存されます 列。
    4. ユーザーのタイムゾーンにローカルな時間要求を返します(つまり、UTCから変換します America/Los_Angelesへ 。
    5. データベースのtimezoneを設定します UTCへ 。

    このオプションは、ユーザーのタイムゾーンを取得するのが難しい場合があるため、常に機能するとは限りません。したがって、TIMESTAMP WITH TIME ZONEを使用するためのヘッジアドバイスがあります。 軽量アプリケーション向け。そうは言っても、このオプション4の背景となる側面について詳しく説明しましょう。

    オプション3と同様に、WITH TIME ZONEの理由 何かが起こったのは絶対だからです 時間の瞬間。 WITHOUT TIME ZONE 相対を生成します タイムゾーン。絶対タイムスタンプと相対タイムスタンプを混在させないでください。

    プログラムと一貫性の観点から、すべての計算がタイムゾーンとしてUTCを使用して行われるようにします。これはPostgreSQLの要件ではありませんが、他のプログラミング言語や環境と統合する場合に役立ちます。 CHECKの設定 タイムスタンプ列への書き込みのタイムゾーンオフセットが0であることを確認するために、列で は、いくつかのクラスのバグを防ぐ防御的な位置です(たとえば、スクリプトがデータをファイルにダンプし、他の何かが字句ソートを使用して時間データをソートします)。繰り返しになりますが、PostgreSQLは、日付の計算を正しく行ったり、タイムゾーン間で変換したりするためにこれを必要としません(つまり、PostgreSQLは任意の2つのタイムゾーン間の時刻の変換に非常に優れています)。データベースに送られるデータがゼロのオフセットで保存されるようにするには:

    CREATE TABLE my_tbl (
      my_timestamp TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
      CHECK(EXTRACT(TIMEZONE FROM my_timestamp) = '0')
    );
    test=> SET timezone = 'America/Los_Angeles';
    SET
    test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
    ERROR:  new row for relation "my_tbl" violates check constraint "my_tbl_my_timestamp_check"
    test=> SET timezone = 'UTC';
    SET
    test=> INSERT INTO my_tbl (my_timestamp) VALUES (NOW());
    INSERT 0 1
    

    100%完璧というわけではありませんが、データがすでにUTCに変換されていることを確認するのに十分な強力な反フットシュート対策を提供します。これを行う方法については多くの意見がありますが、これは私の経験から実際に最良のようです。

    データベースのタイムゾーン処理に対する批判は大部分が正当化されますが(これを非常に無能に処理するデータベースはたくさんあります)、PostgreSQLのタイムスタンプとタイムゾーンの処理は非常に優れています(あちこちにいくつかの「機能」があるにもかかわらず)。たとえば、そのような機能の1つ:

    -- Make sure we're all working off of the same local time zone
    test=> SET timezone = 'America/Los_Angeles';
    SET
    test=> SELECT NOW();
                  now              
    -------------------------------
     2011-05-27 15:47:58.138995-07
    (1 row)
    
    test=> SELECT NOW() AT TIME ZONE 'UTC';
              timezone          
    ----------------------------
     2011-05-27 22:48:02.235541
    (1 row)
    

    AT TIME ZONE 'UTC'に注意してください タイムゾーン情報を削除し、相対的なTIMESTAMP WITHOUT TIME ZONEを作成します ターゲットの参照フレームを使用する(UTC

    不完全なTIMESTAMP WITHOUT TIME ZONEから変換する場合 TIMESTAMP WITH TIME ZONE 、欠落しているタイムゾーンは接続から継承されます:

    test=> SET timezone = 'America/Los_Angeles';
    SET
    test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
     date_part 
    -----------
            -7
    (1 row)
    test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
     date_part 
    -----------
            -7
    (1 row)
    
    -- Now change to UTC    
    test=> SET timezone = 'UTC';
    SET
    -- Create an absolute time with timezone offset:
    test=> SELECT NOW();
                  now              
    -------------------------------
     2011-05-27 22:48:40.540119+00
    (1 row)
    
    -- Creates a relative time in a given frame of reference (i.e. no offset)
    test=> SELECT NOW() AT TIME ZONE 'UTC';
              timezone          
    ----------------------------
     2011-05-27 22:48:49.444446
    (1 row)
    
    test=> SELECT EXTRACT(TIMEZONE_HOUR FROM NOW());
     date_part 
    -----------
             0
    (1 row)
    
    test=> SELECT EXTRACT(TIMEZONE_HOUR FROM TIMESTAMP WITH TIME ZONE '2011-05-27 22:48:02.235541');
     date_part 
    -----------
             0
    (1 row)
    

    結論:

    • ユーザーのタイムゾーンを名前付きラベルとして保存します(例:America/Los_Angeles )、UTCからのオフセットではありません(例:-0700
    • ゼロ以外のオフセットを保存するやむを得ない理由がない限り、すべてにUTCを使用します
    • ゼロ以外のすべてのUTC時間を入力エラーとして扱います
    • 相対タイムスタンプと絶対タイムスタンプを混在させないでください
    • UTCも使用します timezoneとして 可能であればデータベースに

    ランダムプログラミング言語ノート:Pythonのdatetime データ型は、絶対時間と相対時間の区別を維持するのに非常に優れています(ただし、最初はPyTZなどのライブラリで補足するまでイライラします)。

    編集

    相対的なものと絶対的なものの違いについてもう少し説明しましょう。

    絶対時間は、イベントを記録するために使用されます。例:「ユーザー123がログインしました」または「卒業式は2011年5月28日午後2時PSTに開始されます。」ローカルタイムゾーンに関係なく、イベントが発生した場所にテレポートできれば、イベントの発生を目撃できます。データベース内のほとんどの時間データは絶対値です(したがって、TIMESTAMP WITH TIME ZONEである必要があります 、理想的には+0オフセットと、オフセットではなく特定のタイムゾーンを管理するルールを表すテキストラベルを使用します。

    相対的なイベントは、まだ決定されていないタイムゾーンの観点から何かの時間を記録またはスケジュールすることです。例:「私たちのビジネスのドアは午前8時に開き、午後9時に閉じます」、「毎週月曜日の午前7時に会議を行い、毎週の朝食会を開きます」、「毎週ハロウィーンの午後8時に」。一般に、相対時間はイベントのテンプレートまたはファクトリで使用され、絶対時間はその他のほとんどすべてに使用されます。相対時間の値を説明する必要がある、指摘する価値のあるまれな例外が1つあります。何かが発生する可能性のある絶対時間について不確実性がある可能性がある将来のイベントについては、相対タイムスタンプを使用します。これが実際の例です:

    2004年で、2008年10月31日の午後1時に米国西海岸で配達をスケジュールする必要があるとします(例:America/Los_Angeles / PST8PDT )。 ’2008-10-31 21:00:00.000000+00’::TIMESTAMP WITH TIME ZONEを使用して絶対時間を使用して保存した場合 、米国政府が夏時間を管理する規則を変更した2005年のエネルギー政策法を可決したため、配達は午後2時に表示されます。配信が予定されていた2004年の日付10-31-2008 太平洋標準時(+8000 )、ただし2005年以降、タイムゾーンデータベースは10-31-2008を認識しました。 パシフィック夏時間(+0700 )。相対タイムスタンプをタイムゾーンに保存すると、議会の情報に基づく改ざんの影響を受けないため、正しい配信スケジュールが得られます。スケジュールに相対時間と絶対時間を使用することのカットオフはあいまいな線ですが、私の経験則では、3〜6か月を超える将来のスケジュールでは、相対タイムスタンプを使用する必要があります(スケジュール=絶対vs計画=相対???)。

    他の/最後のタイプの相対時間はINTERVALです 。例:「ユーザーがログインしてから20分後にセッションがタイムアウトします」。 INTERVAL どちらの絶対タイムスタンプでも正しく使用できます(TIMESTAMP WITH TIME ZONE )または相対タイムスタンプ(TIMESTAMP WITHOUT TIME ZONE )。 「ログインに成功してから20分後にユーザーセッションが期限切れになる(login_utc + session_duration)」または「朝の朝食会は60分しか続かない(recurring_start_time + Meeting_length)」と言うのも同様に正しいです。

    混乱の最後のビット:DATETIMETIME WITHOUT TIME ZONE およびTIME WITH TIME ZONE すべて相対データ型です。例:'2011-05-28'::DATE 深夜を識別するために使用できるタイムゾーン情報がないため、相対的な日付を表します。同様に、'23:23:59'::TIME タイムゾーンもDATEもわからないため、相対的です 時間で表されます。 '23:59:59-07'::TIME WITH TIME ZONEでも 、DATEがわからない だろう。そして最後に、DATE タイムゾーンのあるものは実際にはDATEではありません 、TIMESTAMP WITH TIME ZONE

    test=> SET timezone = 'America/Los_Angeles';
    SET
    test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
          timezone       
    ---------------------
     2011-05-11 07:00:00
    (1 row)
    
    test=> SET timezone = 'UTC';
    SET
    test=> SELECT '2011-05-11'::DATE AT TIME ZONE 'UTC';
          timezone       
    ---------------------
     2011-05-11 00:00:00
    (1 row)
    

    日付とタイムゾーンをデータベースに入れるのは良いことですが、微妙に間違った結果を得るのは簡単です。 時間情報を正確かつ完全に保存するために必要な追加の作業は最小限ですが、それは常に追加の作業が必要であることを意味するわけではありません。



    1. MySQLとMariaDBで大量のデータを処理する

    2. PL / SQLで文字列を分割する機能はありますか?

    3. MySQLエラー1290(HY000)--secure-file-privオプション

    4. SQLServerで正方形を計算する方法