Java Date-Time API中的基本类

Java Date-Time API中的基本类,用户希望使用 java.time 包引入的类来处理日期和时间,可以使用 InstantDurationPeriodLocalDateLocalTimeLocalDateTimeZonedDateTime 等类定义的工厂方法。

Java Date-Time API中的基本类 问题描述

用户希望使用 java.time 包引入的类来处理日期和时间。

Java Date-Time API中的基本类 解决方案

使用 InstantDurationPeriodLocalDateLocalTimeLocalDateTimeZonedDateTime 等类定义的工厂方法。

Java Date-Time API中的基本类 具体实例

Date-Time API 中的所有类均生成不可变实例,它们是线程安全的。由于这些类不提供公共构造函数(public constructor),需要采用工厂方法加以实例化。
读者应对 nowof 这两种静态工厂方法予以特别注意。now 方法根据当前日期或时间创建实例,示例代码如例 8-1 所示。

例 8-1 工厂方法 now

System.out.println("Instant.now():       " + Instant.now());
System.out.println("LocalDate.now():     " + LocalDate.now());
System.out.println("LocalTime.now():     " + LocalTime.now());
System.out.println("LocalDateTime.now(): " + LocalDateTime.now());
System.out.println("ZonedDateTime.now(): " + ZonedDateTime.now());

上述代码的输出如例 8-2 所示。

例 8-2 调用 now 方法的结果

Instant.now():       2017-06-20T17:27:08.184Z
LocalDate.now():     2017-06-20
LocalTime.now():     13:27:08.318
LocalDateTime.now(): 2017-06-20T13:27:08.319
ZonedDateTime.now(): 2017-06-20T13:27:08.319-04:00[America/New_York]

如例 8-2 所示,所有输出值均使用 ISO 8601 标准格式。日期的基本格式为 yyyy-MM-dd,而时间的基本格式为 hh:mm:ss.sssLocalDateTime 类将两种格式合二为一,中间用大写字母 T 隔开。ZonedDateTime 类用于显示包含时区信息的日期和时间,其后添加了一个 UTC 偏移量(UTC offset)以及一个地区名(region name),本例分别为 -04:00America/New_York。此外,Instant 类定义的 toString 方法将输出以祖鲁时间(Zulu time)1 显示的当前时间(精确到纳秒)。
1即 UTC 时间,因为北约音标字母(NATO phonetic alphabet)采用“Zulu”表示“Z”,而“Z”在 UTC 中表示零时区。例如,“03:06 UTC”可以表示为“03:06Z”(“03:06”和“Z”之间没有空格)。——译者注

类似地,YearYearMonthMonthDay 类也定义了 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 方法在日期 / 时间类中的应用

System.out.println("First landing on the Moon:");
LocalDate moonLandingDate = LocalDate.of(1969, Month.JULY, 20);
LocalTime moonLandingTime = LocalTime.of(20, 18);
System.out.println("Date: " + moonLandingDate);
System.out.println("Time: " + moonLandingTime);

System.out.println("Neil Armstrong steps onto the surface: ");
LocalTime walkTime = LocalTime.of(20, 2, 56, 150_000_000);
LocalDateTime walk = LocalDateTime.of(moonLandingDate, walkTime);
System.out.println(walk);

输出如下:

First landing on the Moon:
Date: 1969-07-20
Time: 20:18
Neil Armstrong steps onto the surface:
1969-07-20T20:02:56.150

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 提供:

Set<String> regionNames = ZoneId.getAvailableZoneIds();
System.out.println("There are " + regionNames.size() + " region names");

以 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 方法;有关 parseformat 方法的讨论请参见范例解析与格式化;有关 with 方法的讨论请参见范例根据现有实例创建日期和时间,它是 set 方法的不可变等效形式;有关 plusminus 方法的应用请参见范例根据现有实例创建日期和时间
例 8-4 显示了利用 at 方法为本地日期和时间添加时区。

例 8-4 为 LocalDateTime 添加时区信息

LocalDateTime dateTime = LocalDateTime.of(2017, Month.JULY, 4, 13, 20, 10);
ZonedDateTime nyc = dateTime.atZone(ZoneId.of("America/New_York"));
System.out.println(nyc);

ZonedDateTime london = nyc.withZoneSameInstant(ZoneId.of("Europe/London"));
System.out.println(london);

输出结果如下:

2017-07-04T13:20:10-04:00[America/New_York]
2017-07-04T18:20:10+01:00[Europe/London]

在本例中,withZoneSameInstant 方法传入一个 ZonedDateTime,并查找另一个时区的日期和时间。
java.time 包引入了 MonthDayOfWeek 两种枚举。Month 包括标准日历中 12 个月份的常量(从 JANUARYDECEMBER),也定义了许多便利的方法,如例 8-5 所示。

例 8-5 Month 枚举定义的部分方法

System.out.println("Days in Feb in a leap year: " +
    Month.FEBRUARY.length(true));        ➊
System.out.println("Day of year for first day of Aug (leap year): " +
    Month.AUGUST.firstDayOfYear(true));  ➊
System.out.println("Month.of(1): " + Month.of(1));
System.out.println("Adding two months: " + Month.JANUARY.plus(2));
System.out.println("Subtracting a month: " + Month.MARCH.minus(1));

➊ 参数为 boolean leapYear
输出如下:

Days in Feb in a leap year: 29
Day of year for first day of Aug (leap year): 214
Month.of(1): JANUARY
Adding two months: MARCH
Subtracting a month: FEBRUARY

在本例中,最后两条语句分别使用 plusminus 方法创建了新的实例。

java.time 包中的类是不可变的,如果实例方法(如 plusminuswith)试图修改某个类,将生成一个新的实例。

DayOfWeek 枚举包括表示 7 个工作日的常量(从 MONDAYSUNDAY)。所有工作日的 int 值均遵循 ISO 标准,因此 MONDAY 为 1,SUNDAY 为 7。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程