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

Webアプリケーションでのタイムゾーンの処理

    質問夏時間とタイムゾーンのベストプラクティスをお読みください。あなたのものは基本的に複製です。

    UTCのサーバー

    はい。通常、サーバーのOSはタイムゾーンとしてUTCに設定する必要があります。提供されていない場合は、GMTを使用してください。 またはレイキャビクアイスランドのタイムゾーン。 Java実装は、おそらくこの設定を独自の現在のデフォルトのタイムゾーンとして選択します。

    タイムゾーンを指定

    ただし、UTCに設定されているタイムゾーンに依存しないでください。システム管理者が変更する可能性があります。また、JVM内の任意のアプリの任意のスレッドにある任意のJavaコードは、実行時にJVMの現在のデフォルトのタイムゾーンを変更できます。 TimeZone.setDefaultを呼び出す 。したがって、代わりに、Javaコードでオプションの引数を渡すことにより、常に希望する/予想されるタイムゾーンを指定する習慣をつけてください。

    日時フレームワークによってタイムゾーンがオプションになるのは設計上の欠陥だと思います。プログラマーは、他のすべての人と同じように、プロンプトが表示されない限り、無意識のうちに自分のタイムゾーンの観点から考えるため、オプションであると、無限の混乱が生じます。そのため、日時作業では、この問題に注意が払われないことがよくあります。 JVMのデフォルトが異なるという問題を追加します。ちなみに、Localeも同様です 、同じ問題は、常に明示的に指定する必要があります。

    UTC

    ビジネスロジック、データストレージ、およびデータ交換は、ほとんどの場合UTCで実行する必要があります。ほぼすべてのデータベースには、UTCへの入力を調整してUTCに保存する機能があります。

    ユーザーに日時を提示するときは、予想されるタイムゾーンに合わせて調整してください。日時値をシリアル化するときは、ISO8601文字列形式を使用してください。特にVickyAroraforOracleによる回答を参照してください(私はPostgresの人です)。必ずドキュメントを注意深く読み、データベースの動作を完全に理解するために実験して練習してください。 SQL仕様はこの点に関してあまり詳しく説明されておらず、動作は大きく異なります。

    java.sql

    JavaとJDBCを使用する場合は、java.sql.Timestampを使用することに注意してください。 および関連するデータ型。それらは常に自動的にUTCになります。将来的には、Java8以降に組み込まれたjava.timeフレームワークで定義された新しいデータ型を直接使用するようにJDBCドライバーが更新される予定です。

    java.time

    古いクラスはjava.timeによって時代遅れになっています。 java.timeの使い方を学ぶ 古いjava.util.Date/.Calendarを避けながら、プログラミング生活をより快適にします。

    JDBCドライバーが更新されるまで、java.timeに組み込まれている変換コンビニエンスメソッドを使用できます。次の例を参照してください。ここで、Instant UTCとZonedDateTimeの瞬間です タイムゾーンに合わせて調整されたインスタントです。

    Instant instant = myJavaSqlTimestamp.toInstant();
    ZoneId zoneId = ZoneId.of( "America/Montreal" );
    ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
    

    反対方向に進むため。

    java.sql.Timestamp myJavaSqlTimestamp = java.sql.Timestamp.from( zdt.toInstant() );
    

    元のタイムゾーンが必要な場合は、保存してください

    ビジネス要件で、元の入力データのタイムゾーンが重要であり、覚えておく必要があると考えられる場合は、それをデータベーステーブルの個別の列として明示的に保存します。 UTCからのオフセットを使用できますが、それでは完全な情報は提供されません。タイムゾーンはオフセットプラスです 夏時間などの異常の過去、現在、および将来の処理に関する一連のルール。したがって、America/Montrealなどの適切なタイムゾーン名が最も適切です。 。

    日付のみがあいまいです

    時刻やタイムゾーンなしで、多くの日付のみの値を収集するとおっしゃいました。 java.timeのそのクラスはLocalDateです。 。 LocalTimeと同様 およびLocalDateTime 、「ローカル…」の部分は特定の地域を意味しないため、タイムゾーンがなく、タイムライン上のポイントではありません。実際の意味はありません。

    日付のみの値は定義上あいまいであることに注意してください。いつでも、日付は世界中で異なります。たとえば、パリの真夜中過ぎにフランスは新しい日ですが、モントリオールケベックでは日付はまだ「昨日」です。

    通常、ビジネスでは、あるタイムゾーンは暗黙的であり、無意識のうちに直感的ですらあります。データポイントに関する無意識の直感は、特にソフトウェアでは、長期的にはうまく機能しない傾向があります。どのタイムゾーンが意図されているかを明示することをお勧めします。データベーステーブルの別の列など、目的のゾーンを日付と一緒に保存したり、プログラミングコードにコメントを付けたりすることができます。日時の値を保存する方がはるかに安全で安全だと思います。では、どのようにして日付のみを日時に変換するのでしょうか?

    多くの場合、新しい日は、その日の最初の瞬間である真夜中の次の瞬間です。これは、時刻00:00:00.0を意味すると思われるかもしれません。 しかしいつもではない。夏時間(DST)および場合によっては他の異常により、最初の瞬間が別の壁掛け時計の時間になります。 java.timeに、LocalDateを通過する最初の瞬間の正しい時刻を決定させます。 クラスとそのatStartOfDay メソッド。

    ZoneId zoneId = ZoneId.of( "America/Montreal" );
    LocalDate today = LocalDate.now( zoneId );
    ZonedDateTime todayStart = today.atStartOfDay( zoneId );
    

    一部のビジネスコンテキストでは、新しい日が営業時間として定義(または想定)される場合があります。たとえば、ニューヨークの出版社が「本のドラフトは1月2日までに期限が切れる」と言った場合、現地時間の午前9時を意味するとします。そのタイムゾーンでその日付のその時刻を取得しましょう。

    ZoneId zoneId = ZoneId.of( "America/New_York" );
    ZonedDateTime zdt = ZonedDateTime.of( 2016 , 1 , 2 , 9 , 0 , 0 , 0 , zoneId );
    

    ニュージーランドで働く著者にとって、それはどういう意味ですか? withZoneSameInstantを呼び出して、彼女に提示するために彼女の特定のタイムゾーンに調整します 。

    ZoneId zoneId_Pacific_Auckland = ZoneId.of( "Pacific/Auckland" );
    ZonedDateTime zdt_Pacific_Auckland = zdt.withZoneSameInstant( zoneId_Pacific_Auckland );
    

    データベース

    データベースストレージの場合、Instantに変換します (UTCのタイムライン上の瞬間)そしてjava.sql.Timestampとして渡します 上記のように。

    java.sql.Timestamp ts = java.sql.Timestamp.from( zdt.toInstant() );
    

    データベースから取得したら、ニューヨークの日時に変換し直します。 java.sql.Timestampから変換 Instant 、次にタイムゾーンZoneIdを適用します ZonedDateTimeを取得するには 。

    Instant instant = ts.toInstant();
    ZoneId zoneId = ZoneId.of( "America/New_York" );
    ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
    

    データベースドライバがJDBC4.2以降に準拠している場合は、java.sqlタイプとの間で変換するのではなく、java.timeタイプを直接受け渡し/フェッチできる場合があります。 PreparedStatement::setObjectを試してください およびResultSet::getObject メソッド。



    1. SQL Serverでfloatからvarcharへのキャストが丸められるのはなぜですか?

    2. CSVインポート操作の一部として、単一のステップでテーブルを作成してデータを設定するにはどうすればよいですか?

    3. タイムスタンプのインデックス:インデックス式の関数はIMMUTABLEとしてマークする必要があります

    4. カラム側の暗黙的な変換はどれくらいの費用がかかりますか?