web-dev-qa-db-ja.com

LocalDateTimeをJava 8で日付に変換する方法

デフォルトでブラジルのタイムゾーンを使用していますが、ニューヨークのLocalDateTimeを1つキャッチしてJava.tim.Instantに変換すると、instantが正しく入力されます。問題は、ニューヨークのdateを生成する代わりにDate.from(instantValue)Dateを生成しようとするとブラジルから現在の日付を取得することになります。

ZoneId nyZone = ZoneId.of("America/New_York");
ZoneId brazilZone = ZoneId.of("America/Recife");

LocalDateTime ldtBrazil = LocalDateTime.now(brazilZone);
LocalDateTime ldtNY = LocalDateTime.now(nyZone);

Instant instantBrazil = ldtBrazil.toInstant(ZoneOffset.UTC);
Instant instantNY = ldtNY.toInstant(ZoneOffset.UTC);

System.out.println("-------LocalDateTime-------");
System.out.println("ldtBrazil    : "+ldtBrazil);
System.out.println("ldtNY        : "+ldtNY);

System.out.println("\n-------Instant-------");
System.out.println("instantBrazil: "+instantBrazil);
System.out.println("instantNY    : "+instantNY);

long milliBrazil = instantBrazil.toEpochMilli();
long milliNY = instantNY.toEpochMilli();

System.out.println("\n----------Milli----------");
System.out.println("miliBrazil : "+milliBrazil);
System.out.println("miliNY     : "+milliNY);

Date dateBrazil = Date.from(instantBrazil);
Date dateNY = Date.from(instantNY);

System.out.println("\n---------Date From Instant---------");
System.out.println("dateBrazil: "+dateBrazil);
System.out.println("dateNY    : "+dateNY);

System.out.println("\n---------Date From Milli---------");
System.out.println("dateBrazil: "+new Date(milliBrazil));
System.out.println("dateNY    : "+new Date(milliNY));

結果

-------LocalDateTime-------
ldtBrazil    : 2016-09-21T22:11:52.118
ldtNY        : 2016-09-21T21:11:52.118

-------Instant-------
instantBrazil: 2016-09-21T22:11:52.118Z
instantNY    : 2016-09-21T21:11:52.118Z

----------Milli----------
miliBrazil : 1474495912118
miliNY     : 1474492312118

---------Date From Instant---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016 //this data must be related to   NY LocalDateTime, but reiceved a same date of Brazil.

---------Date From Milli---------
dateBrazil: Wed Sep 21 19:11:52 BRT 2016
dateNY    : Wed Sep 21 18:11:52 BRT 2016
10

LocalDateTimeはゾーンなしを意味します

LocalDateTime の目的を誤解しているようです。

このクラスにはタイムゾーンも TCからのオフセット もありません。それはnotタイムライン上のポイントです。むしろ、可能性のある瞬間についてのあいまいな考えを表しています。 「Local…」という名前は、notが特定の地域を表すのではなく、直感的ではないかもしれませんが、anyの地域を表します。

たとえば、今年のクリスマスは、2016年12月25日の午前0時、または2016-12-25T00:00です。タイムゾーンを適用して、オークランドNZまたはコルカタINまたはパリFRまたはモントリオールCAでクリスマスを迎えるまで、意味はありません。

LocalDateTime を使用しないでください。ゾーンとオフセットの手間が省けると思うからです。それとは逆に、あいまいな日時値のある穴を掘り下げます。

UTCに焦点を当てる

ほとんどのビジネスロジック、ロギング、データストレージ、およびデータ交換はすべて [〜#〜] utc [〜#〜] にある必要があります。 UTCを1つの真の時間と考えてください。他のすべてのゾーンとオフセットは、ドレスアップされたUTC値を装います。

Java.timeでは、Instantクラスがgo-toクラスであり、日時オブジェクトの基本的なビルディングブロックです。 Instant クラスは、 [〜#〜] utc [〜#〜] のタイムライン上の瞬間を nanoseconds の解像度で表します。

Instant now = Instant.now();

ZonedDateTime

一部の地域の 壁時計時間 にアクセスする必要がある場合にのみ、タイムゾーンに調整します。 ZoneIdを適用して、ZonedDateTimeオブジェクトを取得します。

ZoneId zNewYork = ZoneId.of("America/New_York");
ZoneId zRecife = ZoneId.of("America/Recife");

ZonedDateTime zdtNewYork = now.atZone( zNewYork );
ZonedDateTime zdtRecife = now.atZone( zRecife );

これら3つのオブジェクト、nowzdtNewYork、およびzdtRecifeはすべてすべての瞬間、タイムライン上の同じ同時ポイントです。3つすべてが同じエポックからのカウントを共有しています。唯一の違いはレンズスルーです時計の時刻が表示されます。

レガシーの日時クラスを避ける

最も古いバージョンのJavaにバンドルされている面倒な古い日時クラスの使用は避けてください。したがって、Java.util.DateJava.util.Calendarは避けてください。彼らは本当に悪いです。 Java.timeクラスに固執します。

Java.time型用にまだ更新されていない古いコードを操作する必要がある場合は、Java.time型との間で変換できます。古いクラスに追加された新しいメソッドを探します。 Java.util.Date.from メソッドはInstantを取ります。 InstantまたはZoneDateTime)からOffsetDateTimeを抽出できます。

Java.util.Date utilDate = Java.util.Date.from( zdtNewYork.toInstant() );

そして、他の方向に向かっています。

Instant instant = utilDate.toInstant();

変換の詳細については、 my Answer を質問に、 Java.util.Dateを「Java.time」型に変換しますか? を参照してください。

エポックからカウントしない

UTCで1970年のミリ秒などのエポックからのカウント数の使用は避けてください。カウントに使用されるさまざまな粒度(ミリ秒、マイクロ秒、ナノ秒、整数秒など)があります。 1970年以外にもさまざまなコンピューターシステムで使用されているエポックが少なくとも数十あります。数字は人間が読むと意味がないため、バグが検出されない可能性があります。

練習するときに役立つかもしれません。 getEpochSecondgetNanoおよびInstantを呼び出すか、切り捨てられた値の場合はtoEpochMilliを呼び出します。


Java.timeについて

Java.time フレームワークは、Java 8以降に組み込まれています。これらのクラスは、面倒な古い legacy date-timeクラスに取って代わります。 Java.util.DateCalendar 、および SimpleDateFormat として。

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

詳細については、 Oracle Tutorial を参照してください。また、Stack Overflowで多くの例と説明を検索してください。指定は JSR 31 です。

Java.timeオブジェクトをデータベースと直接交換できます。 JDBC 4.2 以降に準拠する JDBCドライバー を使用します。文字列もJava.sql.*クラスも必要ありません。

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

_(ThreeTen-Extra プロジェクトは、追加のクラスでJava.timeを拡張します。このプロジェクトは、Java.timeに将来追加される可能性のある証明の場です。 IntervalYearWeekYearQuarter 、および more

20
Basil Bourque

LocalDateTimeInstant(またはDateの違いについて混乱しているように思えますが、これは本質的にInstant)。これらは完全に異なるオブジェクトです。

LocalDateTimeは、特定のカレンダー日付と特定の時刻です。この絵のように考えることができます。

LocalDateTime

または、年、月、日、時間、分、秒と考えることができます。ただし、タイムゾーンはありません。それはまさにカレンダーの言うこと、時計の言うことです。

Instantは瞬間です。たとえば、ニール・アームストロングが最初に月を踏んだ瞬間は、Instantとして表すことができます。 JFKが撃たれた瞬間もそうでした。

繰り返しますが、タイムゾーンはありません。しかし、それはLocalDateTimeとは異なるものです。どのタイムゾーンを書き留めるのかわからない限り、Instantの時間を書き留めることはできません。ああ、そしてDateInstantと同じものです。

したがって、LocalDateTimeInstantの間で変換するには、特定のタイムゾーンを参照する必要があります。ニール・アームストロングが月を踏んだ瞬間を年、月、日、時、分、秒として表現するために;使用するタイムゾーンを知る必要があります。 UTCを使用する場合、1969年7月21日の午前2時56分です。太平洋標準時を使用する場合、1969年7月20日の午後6時56分です。

その知識を武器に、コードを分析しましょう。いくつかのLocalDateTimeオブジェクトから始めました。

  • ldtBrazilはブラジルの現在の時刻-9月21日22:11:52です。
  • ldtNYは、ニューヨークの現在の時刻-9月21日21:11:52です。

次に、UTCを使用してこれらをInstantオブジェクトに変換します。

  • instantBrazilは、Timbuktuで22:11:52になった瞬間です(一年中UTCを使用しています)。
  • instantNYは、ティンブクトゥで21:11:52(インスタントブラジルよりも1時間早い)だった瞬間です。

次に、これらを印刷します。これを行うにはタイムゾーンを知る必要がありますが、それでも構いません。 Instantは、何があってもUTCで出力されます。それがZの意味です。

ここで、Instantオブジェクトをミリ秒数に変換します。いいよこれは、UTC 1970年1月1日の午前0時からのミリ秒数です。 milliNYは、1時間前のInstantに対応するため、milliBrazilよりも明らかに360万少ないです。

次に、InstantオブジェクトをDateオブジェクトに変換します。 DateInstantは同じように表示されますが、印刷方法は異なりますが、実際には何も変わりません。

変換されたDateオブジェクトを印刷します。それはあなたのロケールだからです。 dateNYdateBrazilより1時間早いということはたまたま起こります。ただし、どちらもブラジル時間で印刷されます。これはUTCから3時間遅れています。したがって、それぞれ19:11:52と18:11:52になります。

最後に、ミリ秒単位の数からさらにDateオブジェクトを作成します。ただし、これらの新しいDateオブジェクトは、同じミリ秒数で作成したため、すでにあるdateBrazilおよびdateNYとまったく同じです。そして再び、彼らはブラジルの時間に印刷されます。

6