📆

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.Datejava.sql.Dateの関係

java.sqlパッケージには、日時を表すクラスが3つあります。

  • java.sql.Date
    • 日付(時分秒を持たない)
    • PostgreSQLで言うところのDATE型に対応
  • java.sql.Time
    • 時分秒(日付を持たない)
    • PostgreSQLで言うところのTIME型に対応
  • java.sql.Timestamp
    • 日時(日付・時分秒すべてを持つ)
    • PostgreSQLで言うところのTIMESTAMP型に対応

PostgreSQLの型については公式ドキュメントを参照

そして、これら3つのクラスは全てjava.util.Dateのサブクラスです。

日付・時分秒すべてを持つjava.util.Dateのサブクラスなのに、java.sql.Dateは時分秒を持たない、java.sql.Timeは日付を持たないのは違和感がありますね。何故か分かりませんが、こうなっています。

特にjava.sql.Datejava.util.Dateとクラス名も一緒なので、使うときはimport間違いに気をつけてください。

java.util.Datejava.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.Datejava.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.Datejava.time.LocalDateの関係

java.sql.Datejava.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.Timejava.time.LocalTimejava.sql.Timestampjava.time.LocalDateTimeも同様に変換できます。

Discussion