Java Date-Time API中的基本类,用户希望使用 java.time
包引入的类来处理日期和时间,可以使用 Instant
、Duration
、Period
、LocalDate
、LocalTime
、LocalDateTime
、ZonedDateTime
等类定义的工厂方法。
Java Date-Time API中的基本类 问题描述
用户希望使用 java.time
包引入的类来处理日期和时间。
Java Date-Time API中的基本类 解决方案
使用 Instant
、Duration
、Period
、LocalDate
、LocalTime
、LocalDateTime
、ZonedDateTime
等类定义的工厂方法。
Java Date-Time API中的基本类 具体实例
Date-Time API 中的所有类均生成不可变实例,它们是线程安全的。由于这些类不提供公共构造函数(public constructor),需要采用工厂方法加以实例化。
读者应对 now
和 of
这两种静态工厂方法予以特别注意。now
方法根据当前日期或时间创建实例,示例代码如例 8-1 所示。
例 8-1 工厂方法
now
上述代码的输出如例 8-2 所示。
例 8-2 调用
now
方法的结果
如例 8-2 所示,所有输出值均使用 ISO 8601 标准格式。日期的基本格式为 yyyy-MM-dd
,而时间的基本格式为 hh:mm:ss.sss
。LocalDateTime
类将两种格式合二为一,中间用大写字母 T
隔开。ZonedDateTime
类用于显示包含时区信息的日期和时间,其后添加了一个 UTC 偏移量(UTC offset)以及一个地区名(region name),本例分别为 -04:00
和 America/New_York
。此外,Instant
类定义的 toString
方法将输出以祖鲁时间(Zulu time)1 显示的当前时间(精确到纳秒)。
1即 UTC 时间,因为北约音标字母(NATO phonetic alphabet)采用“Zulu”表示“Z”,而“Z”在 UTC 中表示零时区。例如,“03:06 UTC”可以表示为“03:06Z”(“03:06”和“Z”之间没有空格)。——译者注
类似地,Year
、YearMonth
与 MonthDay
类也定义了 now
方法。
静态工厂方法 of
用于生成新的值。对 LocalDate
类而言,of
方法的参数为年、月(枚举或整型)、日。
所有
of
方法的月份字段经过重载,以接受Month
枚举(如Month.JANUARY
)或起始值为 1 的整数。不过,由于java.util.Calendar
类定义的整型常量从 0 开始(即Calendar.JANUARY
为 0),需注意避免出现差一错误(off-by-one error)。如有可能,应尽量使用Month
枚举。
LocalTime
类定义的 of
方法包括多种重载形式,根据可用的小时、分、秒以及纳秒值获取当前日期。LocalDateTime
类定义的 of
方法同样包括多种重载形式,根据可用的年、月、日、小时、分、秒以及纳秒值获取当前日期和时间。相关应用如例 8-3 所示。
例 8-3
of
方法在日期 / 时间类中的应用
输出如下:
LocalTime.of
方法的最后一个参数是纳秒。本例在数值中使用下划线以增强可读性,这是 Java 7 引入的一个特性。
Instant
类对时间轴上的单一瞬时点(single instantaneous point)建模,可以用于记录应用程序中的事件时间戳。
ZonedDateTime
类将日期和时间与通过 ZoneId
类获取的时区信息结合在一起,时区以 UTC 偏移量的形式表示。
时区 ID 包括两种类型。
- 相对于 UTC/ 格林尼治标准时间的固定偏移量(fixed offset),如
-05:00
。 - 地理区域(geographical region),如
America/Chicago
。
严格来说,还存在第三种时区 ID,即相对于祖鲁时间的偏移量,它由 Z
和相应的数值构成。
java.time.zone.ZoneRules
类定义了调整偏移量的规则,这些规则通过 java.time.zone.ZoneRulesProvider
类载入。ZoneRules
类包括 isDaylightSavings(Instant)
等方法。
静态方法 systemDefault
用于获取系统默认时区(ZoneId
的当前值),而可用时区 ID 的完整列表由静态方法 getAvailableZoneIds
提供:
以 jdk1.8.0_131 为例,它包括 600 个地区名 2。
2或许不只作者感觉地区名的数量是如此之多。
Date-Time API 使用方法名的标准前缀。如果读者熟悉表 8-1 列出的前缀,不难猜出相应方法的用途。3
3根据 Java 官方教程提供的常用前缀表格编写。
表8-1:Date-Time API中各种方法所用的前缀
方法 | 类型 | 用途 |
---|---|---|
of |
静态工厂 | 创建实例 |
from |
静态工厂 | 将输入参数转换为目标类(target class)的实例 |
parse |
静态工厂 | 解析输入字符串 |
format |
实例 | 生成格式化输出 |
get |
实例 | 返回对象状态的一部分 |
is |
实例 | 查询对象状态 |
with |
实例 | 通过修改现有对象的某个元素来创建新对象 |
plus,minus |
实例 | 分别通过现有对象的增减来创建新对象 |
to |
实例 | 将对象转换为另一种类型 |
at |
实例 | 将对象与另一个对象合并 |
前面已讨论过 of
方法;有关 parse
和 format
方法的讨论请参见范例解析与格式化;有关 with
方法的讨论请参见范例根据现有实例创建日期和时间,它是 set
方法的不可变等效形式;有关 plus
和 minus
方法的应用请参见范例根据现有实例创建日期和时间。
例 8-4 显示了利用 at
方法为本地日期和时间添加时区。
例 8-4 为
LocalDateTime
添加时区信息
输出结果如下:
在本例中,withZoneSameInstant
方法传入一个 ZonedDateTime
,并查找另一个时区的日期和时间。
java.time
包引入了 Month
和 DayOfWeek
两种枚举。Month
包括标准日历中 12 个月份的常量(从 JANUARY
到 DECEMBER
),也定义了许多便利的方法,如例 8-5 所示。
例 8-5
Month
枚举定义的部分方法
➊ 参数为 boolean leapYear
输出如下:
在本例中,最后两条语句分别使用 plus
和 minus
方法创建了新的实例。
java.time
包中的类是不可变的,如果实例方法(如plus
、minus
或with
)试图修改某个类,将生成一个新的实例。
DayOfWeek
枚举包括表示 7 个工作日的常量(从 MONDAY
到 SUNDAY
)。所有工作日的 int
值均遵循 ISO 标准,因此 MONDAY
为 1,SUNDAY
为 7。