Java 8には、日時に関するまったく新しいAPIがあります。このAPIで最も有用なクラスの1つは、タイムゾーンに依存しない日時付きの値を保持するためのLocalDateTime
です。
この目的でレガシークラスJava.util.Date
を使用しているコードはおそらく数百万行あります。そのため、古いコードと新しいコードをやり取りするときは、この2つの間で変換する必要があります。これを達成するための直接的な方法はないようですが、どうすればそれを行うことができるでしょうか。
短い答え:
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.Date
でtoString()
を呼び出すと、これは奇妙に思えるかもしれません。しかし、そのメソッドは実際には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.Date
をLocalDateTime
にラウンドトリップしてJava.util.Date
に戻ると、夏時間のために別の瞬間になる可能性があります。
追加情報:非常に古い日付に影響する別の違いがあります。 Java.util.Date
は1582年10月15日に変わるカレンダーを使用します。それより前の日付はグレゴリオ暦の代わりにユリウス暦を使用します。対照的に、Java.time.*
は常にISOカレンダーシステム(Gregorianと同等)を使用します。ほとんどのユースケースでは、ISOカレンダーシステムが望みのものですが、1582年より前の日付を比較すると奇妙な効果が生じることがあります。
これが私が思いついたものです(そして、すべての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());
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);
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
デフォルトのタイムゾーンが必要だと確信しているならもっとずっと便利な方法:
Date d = Java.sql.Timestamp.valueOf( myLocalDateTime );
以下は、新しいAPI LocalDateTimeからJava.util.dateに変換するときに機能するようです。
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
逆変換も(うまくいけば)同様の方法で達成できます。
それが役に立てば幸い...
すべてがここにあります: http://blog.progs.be/542/date-to-Java-time
"ラウンドトリップ"の答えは正確ではありません。
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
システムのタイムゾーンがUTC/GMTでない場合は、時間を変更します。
これが最も簡単な方法なのか、最善の方法なのか、または落とし穴があるのかどうかはわかりませんが、うまくいきます。
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();
}
Androidを使用していて threetenbp を使用している場合は、代わりにDateTimeUtils
を使用できます。
例:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
Date.from
はapi 26+でのみサポートされているので使用できません
LocalDateTime
- > Date
の最速の方法は次のとおりです。
Date.from(ldt.toInstant(ZoneOffset.UTC))