1. 概述
Java 8 引入了全新的日期时间 API java.time
,但实际开发中我们仍需处理新旧 API 的转换问题。本文将系统介绍 java.util.Date
与 java.time.LocalDate/LocalDateTime
之间的转换方法,以及 java.sql.Date
的处理技巧。
2. 将java.util.Date转换为java.time.LocalDate
2.1. 使用toInstant()和toLocalDate()
Java 8 为 Date
新增了 toInstant()
方法,这是转换的核心。注意:**Instant
对象与时区无关**,转换时必须指定时区:
public LocalDate convertToLocalDateViaInstant(Date dateToConvert) {
return dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
}
⚠️ 处理1582年10月10日之前的日期时,需设置格里高利历:
GregorianCalendar calendar = new GregorianCalendar();
calendar.setGregorianChange(new Date(Long.MIN_VALUE));
Date dateToConvert = calendar.getTime();
2.2. 使用ofEpochMilli()和toLocalDate()
另一种创建 Instant
的方式,效果与上节相同:
public LocalDate convertToLocalDateViaMilisecond(Date dateToConvert) {
return Instant.ofEpochMilli(dateToConvert.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDate();
}
2.3. 使用ofInstant()(Java 9+)
Java 9 提供了更简洁的转换方法:
public LocalDate convertToLocalDate(Date dateToConvert) {
return LocalDate.ofInstant(
dateToConvert.toInstant(), ZoneId.systemDefault());
}
3. 将java.util.Date转换为java.time.LocalDateTime
3.1. 使用toInstant()和toLocalDateTime()
通过 ZonedDateTime
中转转换:
public LocalDateTime convertToLocalDateTimeViaInstant(Date dateToConvert) {
return dateToConvert.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
}
3.2. 使用ofEpochMilli()和toLocalDateTime()
等价实现:
public LocalDateTime convertToLocalDateTimeViaMilisecond(Date dateToConvert) {
return Instant.ofEpochMilli(dateToConvert.getTime())
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
}
3.3. 使用ofInstant()(Java 9+)
推荐写法:
public LocalDateTime convertToLocalDateTime(Date dateToConvert) {
return LocalDateTime.ofInstant(
dateToConvert.toInstant(), ZoneId.systemDefault());
}
4. 将java.time类型转换为java.util.Date
4.1. LocalDate转Date
两种常用方式:
✅ 方式一:使用java.sql.Date(最简单)
public Date convertToDateViaSqlDate(LocalDate dateToConvert) {
return java.sql.Date.valueOf(dateToConvert);
}
✅ 方式二:通过Instant转换
public Date convertToDateViaInstant(LocalDate dateToConvert) {
return java.util.Date.from(dateToConvert.atStartOfDay()
.atZone(ZoneId.systemDefault())
.toInstant());
}
4.2. LocalDateTime转Date
推荐使用 java.sql.Timestamp
:
public Date convertToDateViaSqlTimestamp(LocalDateTime dateToConvert) {
return java.sql.Timestamp.valueOf(dateToConvert);
}
替代方案(通过Instant):
Date convertToDateViaInstant(LocalDateTime dateToConvert) {
return java.util.Date
.from(dateToConvert.atZone(ZoneId.systemDefault())
.toInstant());
}
5. 将java.sql.Date转换为java.time.LocalDate
5.1. 直接使用toLocalDate()
Java 8+ 的 java.sql.Date
已内置转换方法:
public LocalDate convertToLocalDateViaSqlDate(Date dateToConvert) {
return new java.sql.Date(dateToConvert.getTime()).toLocalDate();
}
5.2. 转换为LocalDateTime
使用 java.sql.Timestamp
:
public static LocalDateTime convertToLocalDateTimeViaSqlTimestamp(Date dateToConvert) {
return new java.sql.Timestamp(
dateToConvert.getTime()).toLocalDateTime();
}
6. 总结
本文系统梳理了 Java 日期转换的常见场景:
- ✅
Date
→LocalDate/LocalDateTime
:优先使用ofInstant()
(Java 9+) - ✅
LocalDate/LocalDateTime
→Date
:推荐java.sql.Date/Timestamp
的valueOf()
- ✅
java.sql.Date
→LocalDate
:直接调用toLocalDate()
核心要点:
- 所有转换都需考虑时区(
ZoneId
) - 处理历史日期(1582年前)需特殊设置
- Java 9+ 的
ofInstant()
是最佳实践 - JDBC 类型转换优先使用
java.sql.Date/Timestamp