- 传统方式:使用
java.util.Date - 现代推荐方式:使用 Java 8+ 的
java.timeAPI
概览:SQL 与 Java 日期类型对应关系
了解 SQL 和 Java 中常见的日期/时间类型及其对应关系非常重要。

SQL 类型 (JDBC java.sql 包) |
Java 8+ 类型 (java.time 包) |
描述 |
|---|---|---|
java.sql.Date |
java.sql.Date (已过时) |
仅存储日期(年-月-日),无时间部分,对应 SQL DATE。 |
java.sql.Time |
java.sql.Time (已过时) |
仅存储时间(时-分-秒),无日期部分,对应 SQL TIME。 |
java.sql.Timestamp |
java.time.LocalDateTime |
存储日期和时间,纳秒级精度,对应 SQL TIMESTAMP 或 DATETIME。 |
java.sql.Timestamp |
java.time.Instant |
存储一个时间点,基于 UTC 时区,对应 SQL TIMESTAMP。 |
传统方式 - 使用 java.util.Date
java.util.Date 是 Java 最早引入的日期时间类,但它设计上有很多缺陷(它同时包含日期和时间,但方法如 getDate(), getMonth() 已被废弃,且时区处理混乱),尽管不推荐在新代码中使用,但在维护旧项目时你一定会遇到。
从 java.sql.Date 转换到 java.util.Date
java.sql.Date 是 java.util.Date 的子类,所以转换非常直接。
import java.sql.Date;
import java.util.Date;
public class SqlDateToUtilDate {
public static void main(String[] args) {
// 假设这是从数据库中获取的 java.sql.Date 对象
// PreparedStatement.getDate("birth_date")
java.sql.Date sqlDate = Date.valueOf("2025-10-27"); // 使用 valueOf 从字符串创建
// 直接赋值,因为 java.sql.Date 是 java.util.Date 的子类
java.util.Date utilDate = sqlDate;
System.out.println("java.sql.Date: " + sqlDate);
System.out.println("java.util.Date: " + utilDate);
// 注意:打印时,utilDate 会显示时间部分(通常是 00:00:00)
// 因为 java.util.Date 总是包含日期和时间
}
}
从 java.sql.Timestamp 转换到 java.util.Date
java.sql.Timestamp 也是 java.util.Date 的子类,所以转换同样直接。
import java.sql.Timestamp;
import java.util.Date;
public class SqlTimestampToUtilDate {
public static void main(String[] args) {
// 假设这是从数据库中获取的 java.sql.Timestamp 对象
// PreparedStatement.getTimestamp("create_time")
java.sql.Timestamp sqlTimestamp = Timestamp.valueOf("2025-10-27 10:30:45.123456789");
// 直接赋值
java.util.Date utilDate = sqlTimestamp;
System.out.println("java.sql.Timestamp: " + sqlTimestamp);
System.out.println("java.util.Date: " + utilDate);
// 注意:utilDate 会丢失纳秒级的精度,因为它只精确到毫秒
}
}
现代推荐方式 - 使用 Java 8+ 的 java.time API
自 Java 8 起,官方引入了 java.time 包,它提供了更清晰、更安全、功能更强大的日期时间 API。**强烈建议在所有新项目中使用,`

从 java.sql.Date 转换
java.sql.Date 提供了 toLocalDate() 方法,可以轻松地转换为 java.time.LocalDate。
import java.sql.Date;
import java.time.LocalDate;
public class SqlDateToLocalDate {
public static void main(String[] args) {
java.sql.Date sqlDate = Date.valueOf("2025-10-27");
// 1. 转换为 java.time.LocalDate (最常用)
LocalDate localDate = sqlDate.toLocalDate();
System.out.println("java.sql.Date: " + sqlDate);
System.out.println("java.time.LocalDate: " + localDate); // 格式: 2025-10-27
// 如果需要从 LocalDate 再转回 java.sql.Date (存回数据库)
java.sql.Date sqlDateAgain = Date.valueOf(localDate);
System.out.println("转换回 java.sql.Date: " + sqlDateAgain);
}
}
从 java.sql.Timestamp 转换
java.sql.Timestamp 提供了多个转换方法,非常方便。
import java.sql.Timestamp;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class SqlTimestampToJavaTime {
public static void main(String[] args) {
java.sql.Timestamp sqlTimestamp = Timestamp.valueOf("2025-10-27 10:30:45.123456789");
// 1. 转换为 java.time.LocalDateTime (推荐,无时区信息)
// 这保留了日期和时间,但不带时区信息。
LocalDateTime localDateTime = sqlTimestamp.toLocalDateTime();
System.out.println("java.sql.Timestamp: " + sqlTimestamp);
System.out.println("java.time.LocalDateTime: " + localDateTime); // 格式: 2025-10-27T10:30:45.123456789
// 2. 转换为 java.time.Instant (推荐,表示一个时间点)
// Instant 基于UTC,非常适合用于记录事件或序列化。
Instant instant = sqlTimestamp.toInstant();
System.out.println("java.time.Instant: " + instant); // 格式: 2025-10-27T10:30:45.123Z
// 3. 转换为 java.time.ZonedDateTime (带有时区信息)
// 如果需要将时间与特定时区关联,可以使用这个。
ZoneId defaultZoneId = ZoneId.systemDefault(); // 获取系统默认时区
ZonedDateTime zonedDateTime = instant.atZone(defaultZoneId);
System.out.println("java.time.ZonedDateTime: " + zonedDateTime); // 格式: 2025-10-27T18:30:45.123+08:00[Asia/Shanghai] (假设在中国)
}
}
总结与最佳实践
| 转换场景 | 传统方式 (java.util.Date) |
现代推荐方式 (java.time) |
|---|---|---|
SQL DATE -> Java |
java.sql.Date -> java.util.Date (直接赋值) |
java.sql.Date -> java.time.LocalDate (.toLocalDate()) |
SQL TIMESTAMP -> Java |
java.sql.Timestamp -> java.util.Date (直接赋值) |
java.sql.Timestamp -> java.time.LocalDateTime (.toLocalDateTime()) 或 java.time.Instant (.toInstant()) |
Java -> SQL DATE |
java.util.Date -> java.sql.Date (构造函数) |
java.time.LocalDate -> java.sql.Date (.valueOf()) |
Java -> SQL TIMESTAMP |
java.util.Date -> java.sql.Timestamp (构造函数) |
java.time.Instant -> java.sql.Timestamp (.from(Instant)) |
核心建议:
- 拥抱
java.time:在所有新的 Java 项目中,优先使用java.time包下的类,它们是不可变的,线程安全,API 设计得非常直观。 - 理解
LocalDateTimevsInstant:- 当你关心的是“本地”的日历和时间(用户的生日、会议安排),使用
LocalDateTime。 - 当你关心的是全球统一的一个“时间点”(日志记录、数据库事件时间戳),使用
Instant。
- 当你关心的是“本地”的日历和时间(用户的生日、会议安排),使用
- 数据库驱动层:现代的 JDBC 驱动通常也支持直接从
ResultSet中获取java.time类型的对象,getLocalDate(),getLocalDateTime(),getInstant()等,如果可能,直接使用这些方法,可以避免先获取java.sql类型再转换的麻烦。
