日期时间 API 概述
介绍日期时间 API
时间似乎是一个简单的主题;即使是廉价的手表也能提供相当准确的日期和时间。但是,仔细观察后,你会意识到影响你对时间的理解的微妙复杂性和许多因素。例如,将一个月添加到 1 月 31 日的结果对于闰年和非闰年是不同的。时区也增加了复杂性。例如,一个国家可能会在短时间内进出夏令时,或者一年中不止一次,或者它可能在某一年完全跳过夏令时。
日期时间 API 使用 ISO-8601 中定义的日历系统作为默认日历。此日历基于公历系统,并在全球范围内用作表示日期和时间的实际标准。日期时间 API 中的核心类具有诸如 LocalDateTime
、ZonedDateTime
和 OffsetDateTime
之类的名称。所有这些都使用 ISO 日历系统。如果你想使用其他日历系统,例如伊斯兰历或泰国佛教历,java.time.chrono
包允许你使用预定义的日历系统之一。或者你可以创建自己的。
日期时间 API 使用 Unicode 通用语言环境数据存储库 (CLDR)。此存储库支持世界语言,并包含世界上最大的语言环境数据集合。此存储库中的信息已本地化为数百种语言。日期时间 API 还使用 时区数据库 (TZDB)。该数据库提供有关自 1970 年以来全球每个时区变化的信息,以及自引入时区概念以来主要时区的历史记录。
日期时间设计原则
日期时间 API 是使用几个设计原则开发的。
清晰
API 中的方法定义明确,其行为清晰且符合预期。例如,使用空参数值调用日期时间方法通常会触发 NullPointerException
。
流畅
日期时间 API 提供了一个流畅的接口,使代码易于阅读。由于大多数方法不允许使用空值参数并且不返回空值,因此可以将方法调用链接在一起,并且可以快速理解生成的代码。例如
LocalDate today = LocalDate.now();
LocalDate payday = today.with(TemporalAdjusters.lastDayOfMonth()).minusDays(2);
不可变
日期时间 API 中的大多数类创建不可变的对象,这意味着在创建对象后,无法修改它。要更改不可变对象的值,必须构造一个作为原始对象的修改副本的新对象。这也意味着日期时间 API 本质上是线程安全的。这会影响 API,因为用于创建日期或时间对象的大多数方法都以 of、from 或 with 为前缀,而不是构造函数,并且没有 set 方法。例如
LocalDate dateOfBirth = LocalDate.of(2012, Month.MAY, 14);
LocalDate firstBirthday = dateOfBirth.plusYears(1);
可扩展
日期时间 API 在尽可能的情况下是可扩展的。例如,你可以定义自己的时间调整器和查询,或者构建自己的日历系统。
日期时间包
日期时间 API 由主包 java.time 和四个子包组成
java.time
API 的核心,用于表示日期和时间。它包括用于日期、时间、日期和时间组合、时区、瞬间、持续时间和时钟的类。这些类基于 ISO-8601 中定义的日历系统,并且是不可变的和线程安全的。java.time.chrono
用于表示除默认 ISO-8601 之外的日历系统的 API。你也可以定义自己的日历系统。本教程不会详细介绍此包。java.time.format
用于格式化和解析日期和时间的类。java.time.temporal
扩展 API,主要用于框架和库编写者,允许日期和时间类之间进行互操作、查询和调整。字段 (TemporalField
和ChronoField
) 和单位 (TemporalUnit
和ChronoUnit
) 在此包中定义。java.time.zone
支持时区、时区偏移量和时区规则的类。如果使用时区,大多数开发人员只需要使用ZonedDateTime
以及ZoneId
或ZoneOffset
。
方法命名约定
日期时间 API 在一组丰富的类中提供了一组丰富的方法。方法名称在尽可能的情况下在类之间保持一致。例如,许多类提供了一个 now 方法,该方法捕获与该类相关的当前时刻的日期或时间值。有一些 from 方法允许从一个类转换为另一个类。
方法名称前缀也存在标准化。由于日期时间 API 中的大多数类都是不可变的,因此 API 不包含 set 方法。(创建后,不可变对象的值无法更改。set 方法的不可变等效项是 with。)下表列出了常用的前缀
前缀 | 方法类型 | 用途 |
---|---|---|
of |
静态工厂 | 创建实例,其中工厂主要验证输入参数,而不是转换它们。 |
from |
静态工厂 | 将输入参数转换为目标类的实例,这可能涉及从输入中丢失信息。 |
parse |
静态工厂 | 解析输入字符串以生成目标类的实例。 |
format |
实例 | 使用指定的格式化程序将时间对象中的值格式化为字符串。 |
get |
实例 | 返回目标对象状态的一部分。 |
is |
实例 | 查询目标对象的状态。 |
with |
实例 | 返回目标对象的副本,其中一个元素已更改;这是 JavaBean 上 set 方法的不可变等效项。 |
plus |
实例 | 返回目标对象的副本,其中添加了一段时间。 |
minus |
实例 | 返回目标对象的副本,其中减去了一段时间。 |
to |
实例 | 将此对象转换为另一种类型。 |
at |
实例 | 将此对象与另一个对象组合。 |
上次更新: 2022 年 1 月 27 日