java.util.Dateを簡単にLocalDateやLocalDateTimeに変換する

Java8から java.time が標準APIに入ったが、それ以前に書かれたソースだったり、ライブラリとの兼ね合いで、まだまだ java.util.Date を扱う機会がある。

両方扱うときに困るのが変換方法で、だいたい検索すると LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); みたいなのが出てくる。

もうちょっと簡単に変換できる方法があるのでメモ。

環境

Java8以降

java.util.Dateからjava.time.LocalDateTimeなどへの変換

java.util.Date から直接 java.time.LocalDateTime などへは変換できないが、 java.sql パッケージの Date, Time, Timestamp には、それぞれ対応する java.time パッケージのクラスへの変換処理が、Java8の時点で用意されている。

なので、いったん java.util.Date#getTime() をもとに java.sql パッケージのクラスに変換するなどし、再度 java.time パッケージのクラスへの変換処理を呼んでやればいい。

java.util.Date からの変換であれば LocalDateTime にすることが多いと思うが、 LocalDateTime には日付部分を返す toLocalDate() と時刻部分を返す toLocalTime() があるので、とりあえず Timestamp を経由しておくのが簡単。

java.util.Date date = ...;

LocalDateTime localDateTime = new Timestamp(date.getTime()).toLocalDateTime();
LocalDate localDate = localDateTime.toLocalDate();
LocalTime localTime = localDateTime.toLocalTime();

Date#toInstant()ZoneId#systemDefault() を覚えるよりは、こちらのほうが楽だと思う。

java.time.LocalDateTimeなどからjava.util.Dateへの変換

java.time のクラスから java.util.Date への変換の場合、これまた java.sql パッケージの3クラスに、それぞれ対応する java.time パッケージのクラスを引数に取る valueOf メソッドが用意されている。

これらを使って java.sql パッケージのクラスに変換してやれば、いずれも java.util.Date を継承しているので、 java.util.Date として扱える。

正確に java.util.Dateインスタンスである必要がある場合は、 getTime() した値でコンストラクタを読んでやればいい。

LocalDateTime localDateTime = ...;

Timestamp timestamp = Timestamp.valueOf(localDateTime);
java.sql.Date sqlDate = java.sql.Date.valueOf(localDateTime.toLocalDate());
Time time = Time.valueOf(localDateTime.toLocalTime());

java.util.Date utilDate = new java.util.Date(timestamp.getTime());

これを覚えておくと、任意の日時の java.util.Date の作成が簡単にできるので、ユニットテストが捗る。

LocalDateTime testLocalDateTime = LocalDateTime.of(2021, 12, 19, 17, 30, 00);
Timestamp testTimestamp = Timestamp.valueOf(testLocalDateTime );
java.util.Date testDate = new java.util.Date(testTimestamp.getTime());

振り返り

いずれも、 java.sql パッケージのクラスと、 java.time パッケージのクラスの対応関係だけ覚えておけばいいので、いろんな変換方法を覚えておくよりは簡単かなと思う。

変換処理の検索結果上位に乗ってこないのは、 java.sql パッケージのクラスがあまり使われていないからだろうか?

余談

Groovy v2.5以降だと org.apache.groovy.datetime.extensions.DateTimeExtensions で、変換メソッドが拡張されている。

java.util.Date#toLocalDateTime() および LocalDateTime#toDate() など、相互変換が可能。

java.util.Calendar にも toLocalDateTime() などが拡張されている。