web-dev-qa-db-ja.com

Joda-Time:DateTime、DateMidnight、LocalDateの使用法

Joda-Time ライブラリにはさまざまな日時クラスが含まれています

DateTime --JDKカレンダーの不変の置換
DateMidnight -時刻が深夜に強制される日付を表す不変クラス
LocalDateTime -ローカルの日付と時刻を表す不変のクラス(タイムゾーンなし)

階層化アプリケーションでこれらのクラスをどのように使用しているのでしょうか。

アプリケーションがタイムゾーンを管理する必要がなく、常にUTCで時間を安全に想定できるように、(少なくともサービスレイヤーで)LocalDateTimeを使用するほとんどすべてのインターフェイスを使用することには利点があります。その後、私のアプリはDateTimeを使用して、実行フローの最初の時点でタイムゾーンを管理できます。

また、DateMidnightがどのシナリオで役立つのか疑問に思っています。

31
mickthompson

アプリケーションがタイムゾーンを管理する必要がなく、常にUTCで時間を安全に想定できるように、(少なくともサービスレイヤーで)LocalDateTimeを使用するほとんどすべてのインターフェイスを使用することには利点があります。

ここであなたの考え方が理解できるかわかりません。 LocalDateTimeDateTimeは、まったく異なる2つの概念を表しています。 LocalDateTimeに暗黙のUTCタイムゾーンがあるわけではありません。実際にはnoタイムゾーンがあります(内部的にはDateTimeとして表される場合があります。 UTCタイムゾーンですが、これは単なる実装の詳細であり、それを使用するプログラマーには関係ありません)。

APIドキュメントで確認できます それに対して、DateTimeは "Instant "(世界のタイムラインのポイント、物理的概念)、LocalDateTimeはそのようなことではありません。 LocalDateTimeは実際には Partial 、(「市民」の概念)、別のクラス階層で。クラス名は、残念ながら、LocalDateTimeDateTimeの特殊化であると思わせるかもしれません。そうではありません。

LocalDateTimeはペアと見なす必要があります{DateY/M/D); Timehh:mm:ss.msec)}、時間関連データの「市民」標準表現に対応する一連の数値。 LocalDateTimeが与えられた場合、それを直接DateTimeに変換することはできません。タイムゾーンを指定する必要があります、そして、その変換は私たちを別の種類のエンティティに連れて行きます。 (アナロジー:Javaの文字列とバイトストリーム:それらの間で変換するには、概念的に異なるため、文字セットエンコーディングを指定する必要があります)

アプリケーションでどちらを使用するか...議論の余地がある場合もありますが、Jodatimeの概念を理解すれば、十分に明確になることがよくあります。また、IMOは「レイヤー」とはあまり関係がなく、おそらくユースケースやシナリオとは関係がありません。

自明ではない-borderline-の例:あなたはGoogleで働いており、カレンダーをプログラミングしています。日時を含むイベントをユーザーに管理(追加、表示、変更)させる必要があります(繰り返し発生するイベントは無視します)。たとえば、「2019年7月3日に医師との約束があります。午前10時」。ソフトウェアレイヤーで使用する日時エンティティは何ですか(このユースケースの場合)?私は言うだろう:LocalDateTime。ユーザーは実際には物理的な時点ではなく、常用時を扱っているためです。つまり、手首または自宅に時計を表示する日付と時刻です。彼はタイムゾーンについても考えていません(世界中を旅しているユーザーの特殊なケースは無視しましょう...)そして、ビジネスとプレゼンテーション層では、LocalDateTimeが適切なエンティティのように見えます。

ただし、別のシナリオ、つまりリマインダーもコーディングする必要があるとします。 Googleの内部スケジューラは、ユーザーが保存したイベントがN分後であることを検出すると、ユーザーにリマインダーを送信する必要があります。ここで、「N分後」は完全に「物理的な」時間の概念であるため、ここでは「ビジネス層」はDateTimeを扱います。たとえば、いくつかの選択肢があります。イベントはLocalDateTimeとしてDBに保存されました(つまり、タイムゾーンなしの日時のみ-UTCタイムスタンプを頻繁に使用してそれを表しますが、これは実装の詳細です)。このシナリオ(これのみ)では、それをDateTimeとしてロードする必要があり、おそらくユーザーのプロファイルからタイムゾーンを使用して変換します。

77
leonbloy

leonbloyによる回答 は正しく、非常に重要です。 Joda-Timeプロジェクトを置き換えるJava.timeクラスに翻訳しているだけです。

Java.time

特定の瞬間

タイムラインの特定の瞬間:

  • 常にUTCでは Instant で表されます。
  • 割り当てられたUTCからのオフセットは OffsetDateTime で表されます。
  • 単なるオフセットではなく、フルタイムゾーンを割り当てることは ZonedDateTime で表されます。

これらはすべて、Joda-TimeのInstantDateTimeクラスを置き換えます。これらのJava.timeクラスはすべて、Joda-Timeで使用されるミリ秒に対して nanoseconds の解像度を持っています。

真夜中と一日の始まり

真夜中の場合、Joda-Timeプロジェクトは、「真夜中」は漠然とした非生産的な概念であると結論付けました。真夜中関連のクラスと真夜中は、Joda-Timeの以降のバージョンではすべて非推奨になり、「その日の最初の瞬間」という実用的な概念に置き換えられました。

Java.timeクラスは、「その日の最初の瞬間」アプローチを使用して、同じレッスンを受けました。 atStartOfDayなどのJava.timeクラスでLocalDateメソッドを探します。

1日が00:00から始まると思い込まないでください。夏時間(DST)などの異常は、1日が01:00などの他の時間に開始される可能性があることを意味します。

ZonedDateTime zdt = 
    LocalDate.of( 2017 , Month.MARCH , 12 )                    // Instantiate a date-only value without time zone.
             .atStartOfDay( ZoneId.of( "America/Havana" ) ) ;  // Cuba jumps from 00:00 to 01:00 on Spring DST cut-over.

たとえば、キュ​​ーバが春の夏時間のカットオーバーで午前1時にどのように1日を開始するかをご覧ください。

zdt:2017-03-12T01:00-04:00 [アメリカ/ハバナ]

ゾーン化されていない

タイムライン上の実際の瞬間ではなく、約26〜27時間の範囲で起こりうる瞬間の漠然とした考えを表すには、LocalDateTimeを使用します。このクラスには、UTCからのオフセットまたはタイムゾーンが意図的に含まれていません。

LocalDateTime ldt = LocalDateTime.of( 2017 , Month.JANUARY , 23 , 1 , 2 , 3 , 0 ) ;

ビジネスコンテキストが特定のタイムゾーンを暗示している場合は、それを適用してZonedDateTimeを取得できます。

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ;  // Determine a specific point on timeline by providing the context of a time zone.

Java.timeについて

Java.time フレームワークはJava 8以降に組み込まれています。これらのクラスは、厄介な古い legacy などの日時クラスに取って代わります。 Java.util.DateCalendar 、& SimpleDateFormat

Joda-Time プロジェクトは、現在 メンテナンスモード であり、 Java.time クラスへの移行をアドバイスします。

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

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

ThreeTen-Extra プロジェクトは、Java.timeを追加のクラスで拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある試験場です。 IntervalYearWeekYearQuarter などの便利なクラスがここにあります。 、および more

0
Basil Bourque