java 8 的 java.time api 通过 instant 作为中转点实现与 date/calendar 的安全互转:date→instant→zoneddatetime/localdatetime;calendar→zoneddatetime;反向转换需注意时区指定。

Java 8 引入的 java.time API(新版日期时间 API)比旧版 Date 和 Calendar 更清晰、线程安全且不易出错。转换的关键在于找到正确的“桥梁方法”——它们都定义在新 API 的类中,用于与旧类互操作。
从 Date 转换为 LocalDateTime / Instant / ZonedDateTime
java.util.Date 本质上表示一个时间戳(自 1970-01-01T00:00:00Z 起的毫秒数),对应新 API 中的 Instant。转换分两步:先转 Instant,再根据需要转成带时区或本地时间的类型。
-
Date → Instant:直接调用
date.toInstant() -
Instant → LocalDateTime:需指定时区,例如
instant.atZone(ZoneId.systemDefault()).toLocalDateTime()(注意:这会丢失时区信息,仅保留本地时间) -
Instant → ZonedDateTime:更推荐,保留时区上下文,如
instant.atZone(ZoneId.of("Asia/Shanghai"))
⚠️ 注意:Date.toString() 默认按 JVM 默认时区输出,但其内部值始终是 UTC 时间戳,转换时别误以为它自带本地时区。
从 Calendar 转换为 LocalDateTime / ZonedDateTime
Calendar 包含时区和字段信息,因此比 Date 更丰富。推荐直接转为 ZonedDateTime,再按需提取。
-
Calendar → ZonedDateTime:调用
calendar.toInstant().atZone(calendar.getTimeZone().toZoneId()) -
Calendar → LocalDateTime:不推荐直接转(会丢失时区),如必须,可先转
ZonedDateTime再调用.toLocalDateTime() - 也可用
calendar.get(Calendar.YEAR)等字段手动构造LocalDateTime.of(...),但易出错、不推荐
反向转换:LocalDateTime / Instant → Date 或 Calendar
反向转换主要用于对接遗留 API。
-
Instant → Date:
Date.from(instant) -
LocalDateTime → Date:必须指定时区,例如
localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),再传给new Date(ms) -
ZonedDateTime → Calendar:先转
Instant,再用GregorianCalendar.from(zdt)(返回GregorianCalendar实例,是Calendar子类)
实用建议与避坑点
实际迁移中,这几个细节常被忽略:
- 别用
new Date().getTime()+LocalDateTime.ofInstant(Instant.ofEpochMilli(...), ...)绕路,直接用date.toInstant() -
SimpleDateFormat不是线程安全的,而DateTimeFormatter是;替换解析/格式化逻辑时优先用后者 - JDBC 场景下,
PreparedStatement.setObject(idx, localDateTime)已支持(JDBC 4.2+),无需再转Timestamp - 测试时注意时区:用
ZoneId.of("UTC")或固定时区(如"GMT+0")避免环境差异影响结果
不复杂但容易忽略。核心就记住:Instant 是新旧之间最自然的交汇点,所有转换尽量以它为中转。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











