Java 8 的 java.time API 通过线程安全、不可变、语义清晰的设计替代老旧 Date/Calendar/SimpleDateFormat;核心是消除共享可变状态、避免时区歧义、提升可读性,推荐用 DateTimeFormatter、LocalDateTime/ZonedDateTime/Instant 显式区分场景,并统一时区声明。

Java 8 引入的 java.time API(JSR-310)是日期时间处理的重大升级,相比老旧的 Date、Calendar 和 SimpleDateFormat,它线程安全、不可变、语义清晰、设计合理。重构老旧日期代码的核心目标是:**消除共享可变状态、避免时区歧义、提升可读性与可维护性**。
替换 SimpleDateFormat 为 DateTimeFormatter
SimpleDateFormat 不是线程安全的,常被误用为静态变量导致偶发解析错误;而 DateTimeFormatter 是不可变且线程安全的,可安全复用。
- ❌ 老写法(危险):
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - ✅ 优化后:
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
解析:LocalDateTime.parse("2024-05-20 14:30:00", FORMATTER)
格式化:localDateTime.format(FORMATTER) - ⚠️ 注意:若需时区信息(如 "2024-05-20T14:30:00+08:00"),优先用
ZonedDateTime+DateTimeFormatter.ISO_OFFSET_DATE_TIME或自定义带XXX的模式。
用 LocalDateTime/ZonedDateTime 替代 Date 和 Calendar
Date 实际表示的是毫秒时间戳(即“带时区的瞬时时间”但 API 却不体现时区),Calendar 操作繁琐且易出错;新 API 明确区分语义:
-
无时区的日期时间(如业务系统中的“下单时间”字段,仅记录年月日时分秒,不关心所在时区)→ 用
LocalDateTime -
带时区的完整时刻(如日志时间、API 返回的 ISO 时间)→ 用
ZonedDateTime或OffsetDateTime -
纯时间戳(Instant)(如数据库
TIMESTAMP WITH TIME ZONE、分布式事件时间点)→ 用Instant - 避免混用:不要把
new Date().toInstant()当作“转换”,而要明确原始数据的业务含义再选型。
统一时区处理,显式声明而非依赖系统默认
老旧代码常隐式使用 TimeZone.getDefault(),导致环境迁移或容器部署时行为不一致。
立即学习“Java免费学习笔记(深入)”;
- ❌ 避免:
Calendar.getInstance() // 依赖系统默认时区new Date().toInstant().atZone(ZoneId.systemDefault()) // 隐式、不可控 - ✅ 推荐:
ZonedDateTime.now(ZoneId.of("Asia/Shanghai"))Instant.now().atZone(ZoneId.of("UTC"))
在配置或常量类中定义业务所需时区,例如:public static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai"); - 数据库交互时,JDBC 4.2+ 支持直接传
LocalDateTime/OffsetDateTime,避免手动转Timestamp。
简化日期计算与区间操作
旧代码常用 Calendar.add() 或毫秒加减,逻辑晦涩且易错;新 API 提供语义化方法:
- 加减:
localDate.plusDays(7)、zdt.minusMonths(1)、instant.plus(2, ChronoUnit.HOURS) - 区间判断:
Period.between(start, end)(年月日)、Duration.between(start, end)(纳秒级) - 是否在范围内:
time.isAfter(start) && time.isBefore(end),比compareTo()更直观 - 获取月初/月末:
localDate.with(TemporalAdjusters.firstDayOfMonth()),无需手动设日


















