概要
保守案件やフレームワーク連携では、java.util.Date や java.sql.Date が残っている場面に遭遇します。新規コードでは LocalDate を使いたくても、既存の API やライブラリが旧来の Date 型を返してくる限り、変換処理は避けられません。変換自体は数行で書けますが、タイムゾーンの指定を忘れると深夜0時付近で日付がずれる事故が起きます。この記事では java.util.Date、java.sql.Date、LocalDate の相互変換パターンを整理し、タイムゾーン指定の落とし穴、JDBC ドライバー経由でのやりとり、テストで確認すべきポイントを押さえます。
使いどころ
レガシーシステムから取得した java.util.Date を LocalDate に変換して業務ロジックに渡す
JDBC の ResultSet から取得した java.sql.Date を LocalDate として扱い、日付計算に使う
外部 API が返す Date 型のレスポンスを LocalDate に変換して帳票出力に利用する
コード例
import java.time.LocalDate;
public class DateConversion {
private static final ZoneId JST = ZoneId.of("Asia/Tokyo");
public static LocalDate toLocalDate(Date utilDate) {
return utilDate.toInstant()
.atZone(JST)
.toLocalDate();
}
public static Date toUtilDate(LocalDate localDate) {
return Date.from(
localDate.atStartOfDay(JST).toInstant());
}
public static LocalDate fromSqlDate(java.sql.Date sqlDate) {
return sqlDate.toLocalDate();
}
public static java.sql.Date toSqlDate(LocalDate localDate) {
return java.sql.Date.valueOf(localDate);
}
public static void main(String[] args) {
var utilDate = new Date();
var local = toLocalDate(utilDate);
var sqlDate = toSqlDate(local);
System.out.println("util.Date : " + utilDate);
System.out.println("LocalDate : " + local);
System.out.println("sql.Date : " + sqlDate);
var back = toUtilDate(local);
System.out.println("復元 Date : " + back);
}
}Version Coverage
変換ロジック自体は Java 8 と同じ。var 宣言で型推論を使えるため記述が若干簡潔になる。
// Java 17: var で型推論
var utilDate = new Date();
var fromUtil = utilDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
var sqlDate = java.sql.Date.valueOf(fromUtil);Library Comparison
注意点
java.util.Date → LocalDate の変換には ZoneId の指定が必須。省略すると JVM のデフォルトタイムゾーンに依存し、環境によって結果が変わる
java.sql.Date.valueOf(LocalDate) で生成した sql.Date は時刻部分が 00:00:00 になる。Timestamp が必要な場面と混同しないこと
java.util.Date は内部的にミリ秒精度、LocalDate は日付のみ。変換時に時刻情報が切り捨てられる点を意識する
深夜0時をまたぐ処理では、タイムゾーン次第で日付が前日になることがある。テストでは UTC と JST の両方で確認する
FAQ
ZoneId を指定せずにデフォルトタイムゾーンが UTC になっている場合、JST との9時間差で日付が前日になることがあります。
日付のみなら sql.Date、日時が必要なら sql.Timestamp を使います。JDBC の setDate / setTimestamp と対応します。
定数で ZoneId.of("Asia/Tokyo") を定義しておくと、環境依存を排除でき可読性も上がります。