日期时间 API 是 Java 8 发布的最重要的功能之一。Java 一直缺乏一致的日期和时间处理方法,而 Java 8 的日期时间 API 则是核心 Java API 的一项受欢迎的补充。
我们为什么需要新的 Java 日期时间 API?
在我们开始了解 Java 8 日期时间 API 之前,让我们看看为什么我们需要一个新的 API。现有的 Java 日期和时间相关类存在一些问题,其中一些问题包括:
- Java 日期时间类的定义不一致,我们在 java.util 和 java.sql 包中都有日期类。而且,格式化和解析类是在 java.text 包中定义的。
- java.util.Date 类同时包含日期和时间值,而 java.sql.Date 只包含日期值。在 java.sql 包中存在这个类毫无意义。此外,这两个类的名称相同,这本身就是一个非常糟糕的设计。
- 没有明确定义的类来处理时间、时间戳、格式化和解析。我们有 java.text.DateFormat 抽象类用于解析和格式化需求。通常,SimpleDateFormat 类用于解析和格式化。
- 所有日期类都是可变的,因此它们不是线程安全的。这是 Java 日期和日历类的最大问题之一。
- 日期类不提供国际化支持,也没有时区支持。因此引入了java.util.Calendar和java.util.TimeZone类,但它们也存在上述所有问题。
日期和日历类中定义的方法还存在一些其他问题,但上述问题清楚地表明Java需要一个强大的日期时间API。这就是为什么 Joda Time 作为Java日期时间需求的优质替代品发挥了关键作用。
Java 8日期时间设计原则
Java 8日期时间API是 JSR-310 的实现。它旨在克服传统日期时间实现中的所有缺陷。新日期时间API的一些设计原则包括:
-
不可变性:新日期时间API中的所有类都是不可变的,适用于多线程环境。
-
关注点分离:新API清楚地区分了人类可读的日期时间和机器时间(Unix时间戳)。它为日期、时间、日期时间、时间戳、时区等定义了单独的类。
-
清晰度: 方法清晰定义,并在所有类中执行相同的操作。例如,要获取当前实例,我们有now()方法。所有这些类中都定义了format()和parse()方法,而不是为它们单独创建一个类。
-
实用操作:所有新的日期时间API类都带有执行常见任务的方法,例如加、减、格式化、解析、获取日期/时间的各个部分等。
-
可扩展:新的日期时间API在ISO-8601日历系统上工作,但我们也可以将其与其他非ISO日历一起使用。
日期时间API包
Java 8日期时间API由以下包组成。
- java.time:这是新的Java日期时间API的基础包。所有主要的基础类都属于此包,例如LocalDate、LocalTime、LocalDateTime、Instant、Period、Duration等。所有这些类都是不可变的和线程安全的。大多数情况下,这些类足以满足常见需求的处理。
- java.time.chrono:此包定义了非ISO日历系统的通用API。我们可以扩展AbstractChronology类来创建自己的日历系统。
- java.time.format:此包含有用于格式化和解析日期时间对象的类。大多数情况下,我们不会直接使用它们,因为java.time包中的主要类提供了格式化和解析方法。
- java.time.temporal:此包含有关时间对象的临时对象,我们可以使用它来查找与日期/时间对象相关的特定日期或时间。例如,我们可以使用这些来查找月份的第一天或最后一天。您可以轻松识别这些方法,因为它们始终具有“withXXX”格式。
- java.time.zone Package:此包含有关支持不同时区及其规则的类。
Java 8 日期时间 API 类示例
我们已经查看了 Java 日期时间 API 的大部分重要部分。现在是时候查看带有示例的日期时间 API 的最重要类了。
1. LocalDate
LocalDate 是一个不可变类,表示具有默认格式 yyyy-MM-dd 的日期。我们可以使用 now() 方法获取当前日期。我们也可以为年、月和日提供输入参数以创建 LocalDate 实例。
该类提供了一个重载方法,用于获取当前时间的 now() 方法,我们可以传入 ZoneId 参数以获取特定时区的日期。该类提供了与 java.sql.Date 相同的功能。
在注释中提供了 LocalDate 方法的解释。当我们运行这个程序时,我们会得到以下输出。
2. LocalTime
LocalTime是一个不可变类,其实例表示人类可读的时间格式。它的默认格式是hh:mm:ss.zzz。就像LocalDate一样,这个类提供了时区支持,并通过传入小时、分钟和秒作为输入参数来创建实例。
输出:
3. LocalDateTime
LocalDateTime是一个不可变的日期时间对象,表示带有默认格式yyyy-MM-dd-HH-mm-ss.zzz的日期时间。它提供了一个工厂方法,该方法接受LocalDate和LocalTime输入参数以创建LocalDateTime实例。
在这三个示例中,我们看到如果为创建日期/时间提供无效参数,则会抛出java.time.DateTimeException,它是一个RuntimeException,因此我们不需要显式地捕获它。
我们还看到通过传递ZoneId可以获取日期/时间数据,您可以从其JavaDoc中获取支持的ZoneId值列表。当我们运行上述类时,我们得到以下输出。
4.即时
Instant类用于处理机器可读的时间格式。Instant将日期时间存储在Unix时间戳中。
输出:
Java 8日期API实用程序
大多数日期时间主要类提供各种实用方法,如加/减天、周、月等。还有一些其他的实用方法用于使用TemporalAdjuster调整日期以及计算两个日期之间的周期。
输出:
Java 8日期解析和格式化
将日期格式化为不同格式然后解析字符串以获取日期时间对象非常常见。
输出:
Java 日期 API 传统日期时间支持
传统的日期/时间类几乎被所有应用程序使用,因此具有向后兼容性是必不可少的。这就是为什么有几种实用方法可以将传统类转换为新类,反之亦然。
输出:
正如您所见,传统的TimeZone
和GregorianCalendar
类的toString()方法过于冗长,不够用户友好。
结论
I like this new Date Time API a lot. Some of the most used classes will be LocalDate and LocalDateTime. It’s very easy to work with the new classes. And, having similar methods that does a particular job makes it easy to find. It will take some time from moving legacy classes to new Date Time classes, but I believe it will be worth the time and effort.
Source:
https://www.digitalocean.com/community/tutorials/java-8-date-localdate-localdatetime-instant