質問夏時間とタイムゾーンのベストプラクティスをお読みください。あなたのものは基本的に複製です。
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
メソッド。