Java 日期/时间

核心包与设计理念

Java 8 引入的现代日期时间 API(位于 java.time 包及其子包)是对传统 Date、Calendar 等类的彻底重构,旨在解决旧 API 线程不安全、设计混乱、时区处理复杂等问题。其设计理念更符合实际开发需求,API 简洁直观,成为目前 Java 日期时间处理的推荐方案。

  • 核心包:java.time(主包)、java.time.chrono(日历系统)、java.time.format(格式化)等。

  • 设计理念:不可变对象(线程安全)、清晰的类职责划分、支持时区和历法。

核心包与设计理念

设计理念

Java 8 日期时间 API 的设计围绕以下核心思想展开,彻底解决了旧 API 的痛点:

不可变性(Immutability)

所有核心类(如 LocalDate、Instant 等)都是不可变对象,一旦创建,其值无法修改。任何修改操作(如增减天数)都会返回一个新的对象。天然线程安全,无需担心多线程环境下的并发修改问题(旧 API 中的 SimpleDateFormat、Calendar 均为线程不安全)。

清晰的职责划分

每个类专注于特定的日期时间概念,避免了旧 API 中 Calendar 类多功能混杂的问题:

  • 本地日期时间(无时区):LocalDate(仅年月日)、LocalTime(仅时分秒)、LocalDateTime(年月日时分秒)。

  • 带时区的日期时间:ZonedDateTime(包含时区信息)。

  • 时间戳:Instant(UTC 时间轴上的瞬间)。

  • 时间间隔:Duration(秒 / 纳秒级,用于两个时间点之间)、Period(年月日级,用于两个日期之间)。

  • 格式化与解析:DateTimeFormatter(线程安全,替代 SimpleDateFormat)。

Fluent API 与方法链

所有修改或计算方法(如 plusDays()、minusMonths())均返回新对象,支持方法链编程,代码更简洁易读。示例:

LocalDate tomorrow = LocalDate.now().plusDays(1); // 链式调用

基于 ISO 标准日历系统

默认遵循 ISO-8601 标准(国际通用的日期时间格式,如 2023-10-05、14:30:00),同时支持非 ISO 日历系统(如日本日历、泰国佛历等,通过 java.time.chrono 包实现)。

明确的时区与偏移量支持

  • 时区(TimeZone):通过 ZoneId 表示(如 Asia/Shanghai),ZonedDateTime 直接关联时区信息。

  • 偏移量(与 UTC 的时差):通过 ZoneOffset 表示(如 +08:00),OffsetDateTime 支持基于偏移量的日期时间。

解决了旧 API 中时区处理繁琐、需依赖 Calendar 间接处理的问题。

与旧 API 的兼容性

提供了与 java.util.Date、Calendar 等旧类的转换方法(如 Date.from(Instant)、instant.atZone(ZoneId)),方便逐步迁移旧代码。

核心包与主要类

现代日期时间 API 主要包含以下包和核心类:

核心包:java.time

包含最常用的日期时间类,覆盖大多数日常开发场景。

类名

功能描述

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")

格式化与解析:java.time.format

核心类 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);

日历系统扩展:java.time.chrono

包含非 ISO 日历系统的实现,如:

  • JapaneseChronology:日本日历(含平成、令和等年号)。

  • ThaiBuddhistChronology:泰国佛历。

使用示例:

// 日本日历中的日期(令和5年10月5日)
ChronoLocalDate japaneseDate = JapaneseDate.of(5, 10, 5);

时间调整器:java.time.temporal

提供日期时间的灵活调整功能,核心接口 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())逐步过渡。

 

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
其他应用
公众号