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


484

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

java.util.Dateこの目的でレガシークラスを使用しているコードはおそらく数百万行あります。そのため、古いコードと新しいコードをインターフェイスする場合、2つのコード間で変換する必要があります。これを達成するための直接的な方法はないように思われるので、どのようにそれを行うことができますか?




回答:


706

簡潔な答え:

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ず、「日付」ではなく、タイムライン上の瞬間を表します。オブジェクト内に保存される実際のデータは、long1970-01-01T00:00Z(1970 GMT / UTCの開始の真夜中)からのミリ秒数です。

java.util.DateJSR-310と同等のクラスはです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回発生するローカルタイムラインに重複があります。春にはギャップがあり、時間は消えます。atZone(ZoneId)変換によって何が行われるかの詳細については、Javadocを参照してください。

要約するjava.util.Dateと、a LocalDateTimeとa を往復するjava.util.Date場合、夏時間のために別の瞬間になる可能性があります。

追加情報:非常に古い日付に影響する別の違いがあります。java.util.Date1582年10月15日に変更されるカレンダーを使用し、その前の日付はグレゴリオ暦ではなくユリウス暦を使用します。対照的にjava.time.*、ISOカレンダーシステム(グレゴリオ暦に相当)を常に使用します。ほとんどのユースケースでは、ISOカレンダーシステムが必要ですが、1582年より前の日付を比較すると、奇妙な効果が見られる場合があります。


5
明確な説明をありがとうございました。特にjava.util.Dateにタイムゾーンが含まれていないのはなぜですかtoString()。イベントの公式ドキュメントでは、投稿時にこのことを明確に伝えていません。
チェリー

警告: LocalDateTime.ofInstant(date.toInstant()...本来の動作とは異なります。たとえば、このアプローチを使用new Date(1111-1900,11-1,11,0,0,0);するようになり1111-11-17 23:53:28ます。java.sql.Timestamp#toLocalDateTime()結果1111-11-11 00:00:00が前の例にある必要があるかどうかの実装を見てください。

2
非常に古い日付(1582年より前)に関するセクションを追加しました。FWIW、あなたの提案された修正はかなり間違っているかもしれません。java.util.Dateの1111-11-11は、異なるカレンダーシステム(6.5分の違いのために、java.timeの1111-11-18と歴史的に同じ実際の日です。 1900年以前の多くのタイムゾーンで発生します)
JodaStephen

2
java.sql.Date#toInstantスローすることにも注意する価値がありUnsupportedOperationExceptionます。したがってtoInstant、のRowMapper では使用しないでくださいjava.sql.ResultSet#getDate
LazerBass 2017

132

これが私が思いついたものです(そしてすべての日付時間の難問と同様に、それはおそらくいくつかの奇妙なタイムゾーン-うるう年-日光の調整に基づいて反証されるでしょう: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

2
@scottbは私またはそれを質問した人にそれを述べていますか?私の考えに関しては、まあ、jdk 8 APIで変換を明示的に記述しておくといいでしょう-少なくともそれはできたでしょう。いずれにせよ、新しいJava-8機能を含めるためにリファクタリングされ、その方法を知ることが重要であるライブラリはたくさんあります。
コーディネーター

4
@scottbサードパーティのケースが珍しいのはなぜですか?そのいまいましい。1つの例:JDBC 4以下(できれば5ではない)。
ラマン

5
一般的なJSR-310ルールとして、epoch-millisを使用してタイプ間で変換する必要はありません。オブジェクトを使用したより良い代替案が存在します。以下の私の完全な回答を参照してください。上記の回答は、UTCのようなゾーンオフセットを使用している場合にのみ完全に有効です。回答の一部は、America / New_Yorkのような完全なタイムゾーンでは機能しません。
JodaStephen 2014年

2
代わりのInstant.ofEpochMilli(date.getTime())DOdate.toInstant()
ヤギ

1
@goat toInstant()は見栄えがいいですが、arggggh で失敗しますjava.sql.Date!ですから、ついに使いやすくなりますInstant.ofEpochMilli(date.getTime())
vadipp

22

デフォルトのタイムゾーンが必要だと確信している場合は、はるかに便利な方法です。

Date d = java.sql.Timestamp.valueOf( myLocalDateTime );

25
確かにそれは簡単ですが、jdbc関連のものと単純な日付処理を混ぜるのは好きではありません。少なくともIMHOは好きです。
Enrico Giurin 2017年

9
申し訳ありませんが、これは単純な問題の恐ろしい解決策です。それは、オリンピックのロゴのリングの数に等しい5を定義するようなものです。
Madbreaks

7

新しいAPI LocalDateTimeからjava.util.dateに変換すると、次のように機能するようです。

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

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

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


5

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

「往復」の答えは正確ではありません。

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

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


LocalDateTimeからの2回がオーバーラップする秋の1年に1時間の間に行う場合のみ。春の前進は問題を引き起こしません。ほとんどの場合、両方向が正しく変換されます。
David


3

これが最も簡単な方法であるか、最良の方法であるか、または落とし穴があるかどうかはわかりませんが、機能します。

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
行く落とし穴間違いなくありますLocalDateTimeにはDate。夏時間の移行時に、a LocalDateTimeが存在しないか、2回発生する可能性があります。それぞれのケースで何が起こりたいかを考え出す必要があります。
Jon Skeet 2013年

1
ところで、GregorianCalendar新しいjava.timeAPIが置き換えることを目指している古い厄介なAPI に属しています
Vadzim 2017

3

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

例:

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

Date.fromAPI 26以降でのみサポートされているため、使用できません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.