java.util.Dateとjava.sql.Dateとjava.time.LocalDateのややこしい関係
環境
JDK 21
Java 8以降であれば、バージョンが違っていても同じだと思います。たぶん。
各クラスの1行説明
-
java.util.Date- Javaの初期から存在する日時クラス(時分秒も持つ)
-
java.sql.Date- JDBCで利用する日付クラス(時分秒は持たない)
-
java.time.LocalDate- Java 8から導入された日付クラス(時分秒は持たない)
通常の業務ロジックを書くときは、基本的にはjava.time.LocalDateを使うことがほとんどです。
しかし、古いライブラリやロジックではjava.util.Date、DB周りの込み入ったロジックではjava.sql.Dateを使ったりすることもあるかと思います。
java.util.Dateと同様にJavaの初期から存在するクラスでjava.util.Calendarがあります。java.util.Calendarには、java.util.Dateが不得手とする日時の計算をするためのメソッドが定義されています。古いロジックで見ることがあるかもですが、現在ではほとんど使う機会が無いはずです。
java.util.Dateとjava.sql.Dateの関係
java.sqlパッケージには、日時を表すクラスが3つあります。
-
java.sql.Date- 日付(時分秒を持たない)
- PostgreSQLで言うところの
DATE型に対応 -
ResultSet#getDate()の戻り値 -
PreparedStatement#setDate()の引数
-
java.sql.Time- 時分秒(日付を持たない)
- PostgreSQLで言うところの
TIME型に対応 -
ResultSet#getTime()の戻り値 -
PreparedStatement#setTime()の引数
-
java.sql.Timestamp- 日時(日付・時分秒すべてを持つ)
- PostgreSQLで言うところの
TIMESTAMP型に対応 -
ResultSet#getTimestamp()の戻り値 -
PreparedStatement#setTimestamp()の引数
PostgreSQLの型については公式ドキュメントを参照
そして、これら3つのクラスは全てjava.util.Dateのサブクラスです。

日付・時分秒すべてを持つjava.util.Dateのサブクラスなのに、java.sql.Dateは時分秒を持たない、java.sql.Timeは日付を持たないのは違和感がありますね。何故か分かりませんが、このような継承関係になっています。
特にjava.sql.Dateはjava.util.Dateとクラス名も一緒なので、使うときはimport間違いに気をつけてください。
java.util.Dateとjava.time.LocalDateの関係
前述の通り、Java初期からあったのがjava.util.Dateで、java.time.LocalDateは後からJava 8で導入されました。
java.util.Dateは以下のような問題がありました。
- ミュータブルである
- 「2日後」「3時間後」のような日時の計算が面倒
- 「◯ヶ月◯日間」のような期間を扱えない
-
java.util.Dateを文字列フォーマットするSimpleDateFormatクラスがスレッドセーフでない
そこで新しく登場したのがjava.timeパッケージです。上記の問題を解決した、以下のような特徴を備えています。
- イミュータブルである
- 日時を計算するメソッド
- 期間を扱うクラス
- スレッドセーフな
DateTimeFormatterクラス
java.timeパッケージにはかなり多くのクラスがあります。よく使うものは以下のとおりです。
-
LocalDate- 日付(時分秒を持たない)
-
LocalTime- 時分秒(日付を持たない)
-
LocalDateTime- 日時(日付・時分秒すべてを持つ)
java.util.Dateをjava.time.LocalDateTimeに変換することは可能ですが、ちょっぴり面倒です。
import java.util.Date;
import java.time.LocalDateTime;
import java.time.ZoneId;
public class DateConverter {
public static void main(String[] args) {
Date date = new Date();
// Date -> LocalDateTime
LocalDateTime localDateTime = date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
System.out.println("LocalDateTime: " + localDateTime);
// LocalDateTime -> Date
Date convertedDate = Date.from(localDateTime
.atZone(ZoneId.systemDefault())
.toInstant());
System.out.println("Date: " + convertedDate);
}
}
java.sql.Dateとjava.time.LocalDateの関係
java.sql.Dateとjava.time.LocalDateは、変換するメソッドが用意されています。
import java.sql.Date;
import java.time.LocalDate;
public class DateConverter {
public static void main(String[] args) {
Date date = new Date(System.currentTimeMillis());
// Date -> LocalDate
LocalDate localDate = date.toLocalDate();
System.out.println("Converted LocalDate: " + localDate);
// LocalDate -> Date
Date date2 = Date.valueOf(localDate);
System.out.println("Converted Date: " + date2);
}
}
java.sql.Timeとjava.time.LocalTime、java.sql.Timestampとjava.time.LocalDateTimeも同様に変換できます。
Discussion