web-dev-qa-db-ja.com

Java.time.LocalDateTimeとJava.util.Dateの間の変換

Java 8には、日時に関するまったく新しいAPIがあります。このAPIで最も有用なクラスの1つは、タイムゾーンに依存しない日時付きの値を保持するためのLocalDateTimeです。

この目的でレガシークラスJava.util.Dateを使用しているコードはおそらく数百万行あります。そのため、古いコードと新しいコードをやり取りするときは、この2つの間で変換する必要があります。これを達成するための直接的な方法はないようですが、どうすればそれを行うことができるでしょうか。

427
Knut Arne Vedaa

短い答え:

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());

説明:( この質問に基づいてLocalDateについて)

その名前にもかかわらず、Java.util.Dateは「日付」ではなくタイムライン上の瞬間を表します。オブジェクト内に格納されている実際のデータは、1970-01-01T00:00Z(1970 GMT/UTCの開始の深夜0時)以降のミリ秒単位のlongカウントです。

JSR-310のJava.util.Dateと同等のクラスはInstantなので、変換をやり取りするのに便利なメソッドがあります。

Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);

Java.util.Dateインスタンスはタイムゾーンの概念を持ちません。 toStringはタイムゾーンを基準にしているため、Java.util.DatetoString()を呼び出すと、これは奇妙に思えるかもしれません。しかし、そのメソッドは実際にはJavaのデフォルトのタイムゾーンをその場で使用して文字列を提供します。タイムゾーンはJava.util.Dateの実際の状態の一部ではありません。

Instantには、タイムゾーンに関する情報も含まれていません。したがって、Instantから現地の日時に変換するには、タイムゾーンを指定する必要があります。これはデフォルトのゾーン(ZoneId.systemDefault())でも、アプリケーションが制御するタイムゾーン(ユーザー設定のタイムゾーンなど)でも構いません。 LocalDateTimeには、インスタントゾーンとタイムゾーンの両方を取る便利なファクトリメソッドがあります。

Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());

逆に、LocalDateTimeタイムゾーンはatZone(ZoneId)メソッドを呼び出すことによって指定されます。 ZonedDateTimeは直接Instantに直接変換できます。

LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());

LocalDateTimeからZonedDateTimeへの変換は、予期しない動作を引き起こす可能性があることに注意してください。これは、夏時間が原因で、すべての現地日時が存在するわけではないためです。秋/秋には、同じローカル日時が2回発生するローカルタイムラインに重複があります。春には、1時間が消えるギャップがあります。変換が何をするかの定義については atZone(ZoneId) のJavadocを参照してください。

要約すると、Java.util.DateLocalDateTimeにラウンドトリップしてJava.util.Dateに戻ると、夏時間のために別の瞬間になる可能性があります。

追加情報:非常に古い日付に影響する別の違いがあります。 Java.util.Dateは1582年10月15日に変わるカレンダーを使用します。それより前の日付はグレゴリオ暦の代わりにユリウス暦を使用します。対照的に、Java.time.*は常にISOカレンダーシステム(Gregorianと同等)を使用します。ほとんどのユースケースでは、ISOカレンダーシステムが望みのものですが、1582年より前の日付を比較すると奇妙な効果が生じることがあります。

650
JodaStephen

これが私が思いついたものです(そして、すべてのDate Timeの難問と同様に、それはおそらく奇妙なタイムゾーン - うるう年 - 日照調整に基づいて反証されるでしょう:D)

ラウンドトリップ:Date <<->> LocalDateTime

与えられた:Date date = [some date]

(1)LocalDateTime << Instant << Date

    Instant instant = Instant.ofEpochMilli(date.getTime());
    LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

(2)Date << Instant << LocalDateTime

    Instant instant = ldt.toInstant(ZoneOffset.UTC);
    Date date = Date.from(instant);

例:

与えられた:

Date date = new Date();
System.out.println(date + " long: " + date.getTime());

(1)LocalDateTime << Instant << Date

InstantからDateを作成します。

Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);

DateからInstantを作成します(必須ではありませんが、説明のため):

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

LocalDateTimeからInstantを作成します

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);

(2)Date << Instant << LocalDateTime

InstantからLocalDateTimeを作成します。

instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);

DateからInstantを作成します。

date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());

出力は以下のとおりです。

Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

Instant from Date:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574

LocalDateTime from Instant:
2013-11-01T14:13:04.574

Instant from LocalDateTime:
2013-11-01T14:13:04.574Z

Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
124
The Coordinator

デフォルトのタイムゾーンが必要だと確信しているならもっとずっと便利な方法:

Date d = Java.sql.Timestamp.valueOf( myLocalDateTime );
19
Petrychenko

以下は、新しいAPI LocalDateTimeからJava.util.dateに変換するときに機能するようです。

Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());

逆変換も(うまくいけば)同様の方法で達成できます。

それが役に立てば幸い...

7
dizzy

すべてがここにあります: http://blog.progs.be/542/date-to-Java-time

"ラウンドトリップ"の答えは正確ではありません。

LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);

システムのタイムゾーンがUTC/GMTでない場合は、時間を変更します。

3
joe-mojo

これが最も簡単な方法なのか、最善の方法なのか、または落とし穴があるのか​​どうかはわかりませんが、うまくいきます。

static public LocalDateTime toLdt(Date date) {
    GregorianCalendar cal = new GregorianCalendar();
    cal.setTime(date);
    ZonedDateTime zdt = cal.toZonedDateTime();
    return zdt.toLocalDateTime();
}

static public Date fromLdt(LocalDateTime ldt) {
    ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
    GregorianCalendar cal = GregorianCalendar.from(zdt);
    return cal.getTime();
}
3
Knut Arne Vedaa

Androidを使用していて threetenbp を使用している場合は、代わりにDateTimeUtilsを使用できます。

例:

Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

Date.fromはapi 26+でのみサポートされているので使用できません

2
humazed

LocalDateTime - > Dateの最速の方法は次のとおりです。

Date.from(ldt.toInstant(ZoneOffset.UTC))

1