web-dev-qa-db-ja.com

Java 8 date-time:ZonedDateTimeから1日の始まりを取得

これらの間に違いはありますか:

zonedDateTime.truncatedTo(ChronoUnit.DAYS);

zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());

一方を他方よりも好む理由は何ですか?

ありがとう

53
Nazaret K.

修正のために更新:

ほとんどの場合、同じです、冬から夏に切り替えるときのブラジルの次の例を参照してください:

_ZonedDateTime zdt = 
  ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, 
    ZoneId.of("America/Sao_Paulo")); // switch to summer time
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo]
System.out.println(zdt1); // 2015-10-18T01:00-02:00[America/Sao_Paulo]
System.out.println(zdt2); // 2015-10-18T01:00-02:00[America/Sao_Paulo]
_

切り捨てはローカルタイムラインで行われます。 DAYSを選択した場合、深夜を選択します。 javadoc によれば、truncate()- methodは最終的に新しいZonedDateTimeに変換し直し、ギャップのサイズ(1時間)だけ時間を進めます。

Zdtを最初にLocalDateに変換し(時間部分を切り捨て)、次に与えられたタイムゾーンでそのZonedDateTime-部分を探すことは、この状況では事実上同じです。

ただし、夏時間から冬時間に切り替える逆の場合には、1つの例外があります(反例を与えてくれた@Austinに感謝します) 。問題は、オーバーラップ中に使用するオフセットを決定するときです。通常、クラスZonedDateTimeは前のオフセットを使用するように設計/指定されています。 Javadoc からの抜粋も参照してください。

オーバーラップの一般的な戦略は、ローカルの日時がオーバーラップの中間にある場合、前のオフセットが保持されることです。以前のオフセットがない場合、または以前のオフセットが無効な場合、以前のオフセット、通常は「夏」の時間が使用されます。

クラスZonedDateTimeが結果的に独自の仕様に従う場合、両方の手順は依然として同等の意味になります。

_zdt.truncatedTo(ChronoUnit.DAYS);
_

と同等でなければなりません

_zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();
_

しかし、@ Austinの例による実際の動作は、私自身がテストで確認したものです。

_zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();
_

クラスZonedDateTimeの隠された矛盾のように見えます。どちらの方法を優先するかを尋ねられた場合、2番目の方法を推奨しますが、はるかに長く、より多くのキーストロークが必要です。しかし、それが何をするのかをより透明にすることには大きな利点があります。 2番目のアプローチを好むもう1つの理由は次のとおりです。

実際には、現地時間が一日の始まりに等しい最初の瞬間を取得します。それ以外の場合、最初の方法を使用するときは、次のように記述する必要があります。

_zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();
_
48
Meno Hochschild

それらはわずかに異なります。 javadocsによると、 truncatedTo() はオーバーラップの場合にタイムゾーンを保持しようとしますが、 atStartOfDay() は真夜中の最初の発生。

たとえば、キュ​​ーバは午前1時に夏時間を元に戻し、午前12時に戻ります。その遷移後の時間から始めると、atStartOfDay()は12amの最初の出現を返し、truncatedTo()は2番目の出現を返します。

ZonedDateTime zdt = ZonedDateTime.of(2016, 11, 6, 2, 0, 0, 0, ZoneId.of("America/Havana"));
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt);  // 2016-11-06T02:00-05:00[America/Havana]
System.out.println(zdt1); // 2016-11-06T00:00-05:00[America/Havana]
System.out.println(zdt2); // 2016-11-06T00:00-04:00[America/Havana]
31
Austin

別の方法もあります。

zonedDateTime.with(LocalTime.MIN);

切り捨てられたToと同じ結果を生成します

6
nevster