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

java.timeフレームワークで使用するためにPostgresなどのSQLデータベースに予定を保存する

    予定の種類によって異なります。

    予定には2種類あります:

    • タイムゾーンルールの変更を無視した、タイムライン上の特定の時点。
      例:ロケットの打ち上げ。
    • タイムゾーンルールの変更に合わせて調整する必要がある日時。
      例:医療/歯科訪問。

    瞬間

    たとえば、ロケットの打ち上げを予約する場合、日付と時刻は関係ありません。私たちは、(a)天が整列し、(b)好天を期待する瞬間だけを気にします。

    その間に政治家が私たちの打ち上げサイトまたは私たちのオフィスで使用されているタイムゾーンのルールを変更した場合、それは私たちの打ち上げの予定に影響を与えません。ローンチサイトを管理している政治家が夏時間(DST) を採用する場合 、発売の瞬間は変わりません。私たちの事務所を統治する政治家が外交関係のため、30分早く時計を変更する 隣国とのローンチの瞬間は変わりません。

    そのような約束については、はい、あなたのアプローチは正しいでしょう。予定はUTC に記録します。 タイプTIMESTAMP WITH TIME ZONEの列を使用する 。検索時に、ユーザーが希望する任意のタイムゾーンに調整します。

    Postgres などのデータベース 入力に付随する任意のタイムゾーン情報を使用してUTCに調整し、そのタイムゾーン情報を破棄します。 Postgresから値を取得すると、UTCで見られるように、常に時刻付きの日付が表示されます。一部のツールまたはミドルウェアには、データベースからの取得からプログラマーへの配信までの間にデフォルトのタイムゾーンを適用するという反機能がある場合があることに注意してください。ただし、明確にしてください。Postgresは常にタイプTIMESTAMP WITH TIME ZONEの値を保存および取得します。 UTC、常にUTC、および offset-from-UTC ゼロ時間-分-秒の。

    これがJavaコードの例です。

    LocalDate launchDateAsSeenInRome = LocalDate.of( 2021 , 1 , 23 ) ;
    LocalTime launchTimeAsSeenInRome = LocalTime.of( 21 , 0 ) ;
    ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
    // Assemble those three parts to determine a moment.
    ZonedDateTime launchMomentAsSeenInRome = ZonedDateTime.of( launchDateAsSeenInRome , launchTimeAsSeenInRome , zoneEuropeRome ) ;
    

    UTCで同じ瞬間を表示するには、Instantに変換します 。 Instant オブジェクトは、UTCで見られるように常に瞬間を表します。

    Instant launchInstant = launchMomentAsSeenInRome.toInstant() ;  // Adjust from Rome time zone to UTC.
    

    Z 上記の文字列の例の最後にあるのはUTCの標準表記であり、「ズールー」と発音されます。

    残念ながら、JDBC 4.2チームは、Instant または ZonedDateTime 種類。したがって、JDBCドライバー そのようなオブジェクトをデータベースに対して読み取り/書き込みできる場合とできない場合があります。そうでない場合は、単に OffsetDateTime 。 3つのタイプはすべて、タイムライン上の特定のポイントである瞬間を表します。ただし、OffsetDateTime JDBC で必要なサポートがあります 4.2 私を逃れる理由で。

    OffsetDateTime odtLaunchAsSeenInRome = launchMomentAsSeenInRome.toOffsetDateTime() ;
    

    データベースへの書き込み。

    myPreparedStatement.setObject( … , odtLaunchAsSeenInRome ) ;
    

    データベースからの取得。

    OffsetDateTime launchMoment = myResultSet.getObject( … , OffsetDateTime.class ) ;
    

    ユーザーが希望するニューヨークのタイムゾーンに調整します。

    ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
    ZonedDateTime launchAsSeenInNewYork = launchMoment.atZoneSameInstant( zoneAmericaNewYork ) ;
    

    上記のすべてのコードがIdeOne.comでライブで実行されているのを見ることができます 。

    ちなみに、過去の出来事を追跡することも瞬間として扱われます。患者が実際に予約のために到着したのはいつですか、顧客が請求書を支払ったのはいつですか、新入社員がドキュメントに署名したのはいつですか、サーバーはいつクラッシュしましたか...これらはすべてUTCで瞬間として追跡されます。上で説明したように、通常はInstant 、ただしZonedDateTimeOffsetDateTime また、瞬間を表します。データベースには、TIMESTAMP WITH TIME ZONEを使用します (WITHOUTではありません 。

    時刻

    ほとんどのビジネス指向のアプリは、特定の瞬間ではなく時刻のある日付を目指す、他のタイプの予定に焦点を合わせていると思います。

    ユーザーが医療提供者とテストの結果を確認するための予約をする場合、ユーザーはその日の特定の時刻にそれを行います。その間に、政治家がタイムゾーンのルールを変更し、時計を1時間、30分、またはその他の時間の前後に移動した場合、その医療予約の日付と時刻は同じままです。実際には、元の予定のタイムラインのポイントは、政治家がタイムゾーンを変更した後に変更され、タイムラインの前/後のポイントにシフトします。

    そのような予定については、しません。 UTCで表示される日付と時刻を保存します。 しない データベースの列タイプTIMESTAMP WITH TIME ZONEを使用します 。

    そのような予定については、タイムゾーンに関係なく、時刻とともに日付を保存します。タイプTIMESTAMP WITHOUT TIME ZONEのデータベース列を使用します (WITHOUTに注意してください WITHではなく )。 Javaで一致するタイプはLocalDateTimeです。 。

    LocalDate medicalApptDate = LocalDate.of( 2021 , 1 , 23 ) ;
    LocalTime medicalApptTime = LocalTime.of( 21 , 0 ) ;
    LocalDateTime medicalApptDateTime = LocalDateTime.of( medicalApptDate , medicalApptTime ) ;
    

    それをデータベースに書き込んでください。

    myPreparedStatement.setObject( … , medicalApptDateTime ) ;
    

    これを明確にしてください:LocalDateTime オブジェクトはしません 瞬間を表しますが、ではありません タイムライン上の特定のポイント。 LocalDateTime オブジェクトは、可能なの範囲を表します タイムラインの約26〜27時間に沿った瞬間(世界中のタイムゾーンの範囲)。 LocalDateTimeに本当の意味を与えるため 、目的のタイムゾーンを関連付ける必要があります。

    その目的のタイムゾーンでは、2番目の列を使用してゾーン識別子を格納します。たとえば、文字列Europe/Rome またはAmerica/New_Yorkゾーン名のリスト を参照してください。 。

    ZoneId zoneEuropeRome = ZoneId.of( "Europe/Rome" ) ;
    

    それをテキストとしてデータベースに書き込みます。

    myPreparedStatement.setString( … , zoneEuropeRome ) ;
    

    検索。ゾーン名をテキストとして取得し、ZoneIdをインスタンス化します オブジェクト。

    LocalDateTime medicalApptDateTime = myResultSet.getObject( … , LocalDateTime.class ) ;
    ZoneId medicalApptZone = ZoneId.of( myResultSet.getString( … ) ) ;
    

    これら2つの要素を組み合わせて、ZonedDateTimeとして表される瞬間を決定します。 物体。カレンダーをスケジュールする必要がある場合は、これを動的に実行します。ただし、しない 瞬間を保存します。将来、政治家がタイムゾーンを再定義する場合は、別の瞬間を計算する必要があります。

    ZonedDateTime medicalApptAsSeenInCareProviderZone = ZonedDateTime.of( medicalApptDateTime , medicalApptZone ) ;
    

    ユーザーは米国ニューヨークに旅行しています。彼らは、ニューヨークの一時的な場所にある壁の時計に従って、イタリアのミラノの医療提供者にいつ電話するかを知る必要があります。したがって、あるタイムゾーンから別のタイムゾーンに調整します。同じ瞬間、異なる実時間。

    ZoneId zoneAmericaNewYork = ZoneId.of( "America/New_York" ) ;
    ZonedDateTime medicalApptAsSeenInNewYork = medicalApptAsSeenInCareProviderZone.withZoneSameInstant( zoneAmericaNewYork ) ;
    

    tzdata

    希望するタイムゾーンのルールが変更される可能性がある場合は、コンピューター上のタイムゾーン定義のコピーを更新する必要があることに注意してください。

    Javaには、 tzdataの独自のコピーが含まれています。 、Postgresデータベースエンジンもそうです。また、ホストオペレーティングシステムも同様です。ここに示されているこの特定のコードは、Javaのみが最新である必要があります。 Postgresを使用してタイムゾーンを調整する場合、その tzdata また、最新である必要があります。また、ログ記録などのために、ホストOSを最新の状態に保つ必要があります。ユーザーが適切に時計を監視するには、クライアントマシンのOSも最新である必要があります。

    注意:世界中の政治家は、驚くべき頻度でタイムゾーンを変更する傾向を示しており、多くの場合、事前の警告はほとんどありません。

    java.timeについて

    java.time フレームワークはJava8以降に組み込まれています。これらのクラスは、厄介な古いレガシー に取って代わります。 java.util.Date Calendar 、&​​ SimpleDateFormat

    詳細については、Oracleチュートリアルを参照してください。 。そして、StackOverflowで多くの例と説明を検索してください。仕様は JSR310 です。 。

    Joda-Time プロジェクト、現在メンテナンスモード java.time クラス。

    java.timeを交換できます データベースに直接オブジェクトを追加します。 JDBCドライバー を使用します JDBC4.2 に準拠 またはそれ以降。文字列は必要ありません。java.sql.*も必要ありません。 クラス。 Hibernate5およびJPA2.2はjava.timeをサポートします 。

    java.timeクラスはどこで入手できますか?



    1. コメントの総数を数える方法

    2. Oracle:OALL8は一貫性のない状態にあります

    3. Windows認証を使用したcx_Oracle

    4. MySQLに多数の行を挿入するにはどうすればよいですか?