Java 8 引入的现代日期时间 API(位于 java.time 包及其子包)是对传统 Date、Calendar 等类的彻底重构,旨在解决旧 API 线程不安全、设计混乱、时区处理复杂等问题。其设计理念更符合实际开发需求,API 简洁直观,成为目前 Java 日期时间处理的推荐方案。
核心包:java.time(主包)、java.time.chrono(日历系统)、java.time.format(格式化)等。
设计理念:不可变对象(线程安全)、清晰的类职责划分、支持时区和历法。
Java 8 日期时间 API 的设计围绕以下核心思想展开,彻底解决了旧 API 的痛点:
所有核心类(如 LocalDate、Instant 等)都是不可变对象,一旦创建,其值无法修改。任何修改操作(如增减天数)都会返回一个新的对象。天然线程安全,无需担心多线程环境下的并发修改问题(旧 API 中的 SimpleDateFormat、Calendar 均为线程不安全)。
每个类专注于特定的日期时间概念,避免了旧 API 中 Calendar 类多功能混杂的问题:
本地日期时间(无时区):LocalDate(仅年月日)、LocalTime(仅时分秒)、LocalDateTime(年月日时分秒)。
带时区的日期时间:ZonedDateTime(包含时区信息)。
时间戳:Instant(UTC 时间轴上的瞬间)。
时间间隔:Duration(秒 / 纳秒级,用于两个时间点之间)、Period(年月日级,用于两个日期之间)。
格式化与解析:DateTimeFormatter(线程安全,替代 SimpleDateFormat)。
所有修改或计算方法(如 plusDays()、minusMonths())均返回新对象,支持方法链编程,代码更简洁易读。示例:
LocalDate tomorrow = LocalDate.now().plusDays(1); // 链式调用
默认遵循 ISO-8601 标准(国际通用的日期时间格式,如 2023-10-05、14:30:00),同时支持非 ISO 日历系统(如日本日历、泰国佛历等,通过 java.time.chrono 包实现)。
时区(TimeZone):通过 ZoneId 表示(如 Asia/Shanghai),ZonedDateTime 直接关联时区信息。
偏移量(与 UTC 的时差):通过 ZoneOffset 表示(如 +08:00),OffsetDateTime 支持基于偏移量的日期时间。
解决了旧 API 中时区处理繁琐、需依赖 Calendar 间接处理的问题。
提供了与 java.util.Date、Calendar 等旧类的转换方法(如 Date.from(Instant)、instant.atZone(ZoneId)),方便逐步迁移旧代码。
现代日期时间 API 主要包含以下包和核心类:
包含最常用的日期时间类,覆盖大多数日常开发场景。
类名 | 功能描述 |
LocalDate | 表示无时区的日期(仅含年月日),月份从 1 开始(1=1 月,12=12 月)。 LocalDate.of(2023, 10, 5) → 2023-10-05 |
LocalTime | 表示无时区的时间(仅含时分秒,支持纳秒精度)。 LocalTime.of(14, 30, 25) → 14:30:25 |
LocalDateTime | 表示无时区的日期时间(年月日 + 时分秒),是 LocalDate 与 LocalTime 的组合。 LocalDateTime.of(2023, 10, 5, 14, 30) → 2023-10-05T14:30 |
Instant | 表示UTC 时间轴上的瞬间(时间戳),精确到纳秒,相当于旧 API 的 Date。 Instant.now() → 2023-10-05T06:30:25Z(UTC 时间) |
ZonedDateTime | 表示带时区的日期时间,包含时区信息(ZoneId),可处理跨时区转换。 ZonedDateTime.now(ZoneId.of("Asia/Shanghai")) → 2023-10-05T14:30:25+08:00[Asia/Shanghai] |
Duration | 表示两个时间点之间的时间间隔(基于秒 / 纳秒,适用于 LocalTime、Instant 等)。 Duration.between(LocalTime.of(10,0), LocalTime.of(12,30)) → PT2H30M(2 小时 30 分钟) |
Period | 表示两个日期之间的间隔(基于年月日,适用于 LocalDate)。 Period.between(LocalDate.of(2023,1,1), LocalDate.of(2023,10,5)) → P9M4D(9 个月 4 天) |
ZoneId | 表示时区(如 Asia/Shanghai、UTC),替代旧 API 的 TimeZone。 ZoneId.of("Europe/London") |
ZoneOffset | 表示与 UTC 的偏移量(如 +08:00、-05:00)。 ZoneOffset.of("+08:00") |
核心类 DateTimeFormatter,它是线程安全的日期时间格式化器,替代旧 API 的 SimpleDateFormat。该类支持:
预定义格式:如 ISO_LOCAL_DATE(yyyy-MM-dd)、ISO_LOCAL_TIME(HH:mm:ss)。
自定义格式:通过 ofPattern(String) 定义模式(模式符与 SimpleDateFormat 类似,但更严格)。
示例:
// 格式化 LocalDateTime dt = LocalDateTime.of(2023, 10, 5, 14, 30); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm"); String formatted = dt.format(formatter); // "2023年10月05日 14:30" // 解析 LocalDateTime parsed = LocalDateTime.parse("2023年10月05日 14:30", formatter);
包含非 ISO 日历系统的实现,如:
JapaneseChronology:日本日历(含平成、令和等年号)。
ThaiBuddhistChronology:泰国佛历。
使用示例:
// 日本日历中的日期(令和5年10月5日) ChronoLocalDate japaneseDate = JapaneseDate.of(5, 10, 5);
提供日期时间的灵活调整功能,核心接口 TemporalAdjuster 用于自定义调整逻辑(如 “本月最后一天”“下一个周一”)。
内置调整器通过 TemporalAdjusters 工具类提供:
LocalDate date = LocalDate.of(2023, 10, 5); LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth()); // 2023-10-31 LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY)); // 下一个周一
Java 8 现代日期时间 API 通过不可变性、清晰职责、fluent 风格等设计理念,彻底解决了旧 API 的线程安全、设计混乱等问题。核心包 java.time 提供了覆盖本地日期、时区日期、时间戳等场景的类,配合 DateTimeFormatter 实现安全的格式化 / 解析,成为 Java 日期时间处理的最佳实践。
在新代码中,应优先使用 java.time 包下的类,避免依赖 Date、Calendar 等旧类。对于旧系统迁移,可通过转换方法(如 Date.from(instant)、zonedDateTime.toInstant())逐步过渡。