【译】一文精通 Java 8 时间

JAVA架构日记

共 3634字,需浏览 8分钟

 ·

2021-06-25 08:32

一、背景: 为什么新 API

首先,介绍为什么需要创建新的 API。

1.1 java.util.Date 的问题

  • 非确定(固定)的 – 日期实例不是不可变的。
  • 存在并发性问题 – 日期实例是非线程安全的。
  • 不正确的命名 – Date 不是“日期”,而是“时间戳”(译者注:“泰山”不是泰山,而是一只大猩猩)。
  • 缺乏约定(规范) – 天从1开始,月从0开始,年从1900开始(译者注:这是很让人摸不着头脑的)。
  • 不连续(缺乏“流畅”性) – 不能创建“持续时间”(比如:一个季度、5分钟)或组合(比如:年+月、没有秒的日期)等。

1.2 Java 8 之前的日期时间相关 API

  • System.currentTimeInMillis() 是不准确的,该 API 可以为多个连续调用返回相同的值。
  • java.util.Date vs java.sql.Datejava.sql.Date 只是一个没有时间的 Date。
  • java.sql.Timestampjava.sql.Timestamp 复制的 java.util.Date 添加了纳秒的存储。

1.3 java.util.Calendar 的问题

  • 缺乏清晰度 – 混合了日期和时间。
  • 有混乱的时区支持 – 不太容易切换时区、偏移量等。
  • 存在严重的格式障碍 – SimpleDateFormatCalendar 不能很好地互操作。
  • 带来了扩展的困难 – 难以通过扩展 Calendar 创建新的日历系统。

“ Calendar 对于 Date 来说就相当于贪婪的特拉尔兽(译者注:这种动物蠢得令人难以置信,认为如果你看不见它,它也就看不见你了——迟钝堪比灌木丛,但非常、非常贪婪)“ – 钱德拉·冈图尔(约2000年)。

二、解决方案?

2.1 JSR-310: Date and Time API 摘自 JSR-310 (https://jcp.org/en/jsr/detail?id=310)

  • 主要目标是基于 Java SE 中前两个 API (DateCalendar) 的经验教训,为日期和时间操作提供一个更高级、更全面的模型
  • 新的 API 将针对所有需要日期和时间数据模型的应用程序。这个模型将超越类,取代 DateCalendar包括没有时间的日期、没有日期的时间、持续时间和间隔的表示
  • 新的 API 还将解决相关的日期和时间问题。其中包括 格式化和解析,考虑到 ISO8601 标准 以及它的实现,例如 XML。
  • 新API的最终目标是易于使用。API 将需要包含一些强大的特性,但是不能让这些特性掩盖标准用例。易于使用的一部分包括与现有的 DateCalendar 类的交互……

2.2 JSR-310 的起源

  • JSR-310 的“灵感来自”斯蒂芬·科尔伯恩**_(Stephen Colebourne) _**的非常流行的 Joda-Time 库,他也是 JSR-310 的领导者。
  • JSR-310 是一种既克服缺点又重构 Joda-Time 部分的方法。http://blog.joda.org/2009/11/why-jsr-310-isn-joda-time_4941.html.
  • 检查从 Joda-Time 转换到 Java.time 的 API:http://blog.joda.org/2014/11/convertingfrom-joda-time-to-javatime.html
  • 还可以在 stackoverflow 上查看 Meno Hochschild (Time4J 库的作者)的回答:http://stackoverflow.com/questions/24631909/differences-between-java-8-date-time-apijava-time-and-joda-time

三、Java8 Date Time 类

Dates and Times: 简单的日期和时间 “容器”

类名说明
Instant存储来自 Java 纪元的时间戳 + 纳秒
LocalDate存储没有时间部分的日期(日历日期)
LocalTime存储没有日期部分的时间(挂钟)
LocalDateTime存储日期和时间(LocalDate + Local Time)
ZonedDateTime存储带有时区的日期和时间
OffsetTime存储时间和与 UTC 的偏移量
OffsetDateTime存储带有时间和 UTC 偏移量的日期

Ranges and Partials: 时间跨度和范围

类名说明
Duration以纳秒为单位为时间。(例如:5 分钟)
Period以年、月和(或)天为单位的时间。(例如:2 天)
Month存储月份。(例如:MARCH 三月)
MonthDay存储没有年份或时间的月份和日期(例如:出生日期)
Year存储年份。(例如:2015)
YearMonth存储没有日期或时间的年和月。(例如:信用卡有效期)
DayOfWeek单独存储一周中的某一天。(例如:WEDNESDAY 星期三)

Chronology: 组织和识别日期的日历系统

类名说明
Chronology是创建或获取预建日历系统的工厂默认为 IsoChronology (例如:ThaiBuddhistChronology)
ChronoLocalDate在任意年表中存储没有时间的日期
ChronoLocalDateTime以任意年表存储日期和时间
ChronoZonedDateTime以任意年表形式存储日期、时间和时区
ChronoPeriod模拟天/时间跨度以用于任意年表
Era存储时间线 [通常两个 Chronology,但有时会更多]

四、Java8 Date Time 通用 API 图表

Date and Time:

Ranges:

Partials:

五、流式和语义化的 API

Java 8 日期时间 API 在操作中引入了某种对称性,从而为开发人员带来愉快的编程体验。下面是 API 中通用的方法的前缀列表。

  • of {类工厂方法前缀} – 使用提供的参数构造一个对象——验证和构造不进行转换。示例:LocalDate.of(...) or Instant.ofEpochSecond(...)
  • from {类工厂方法前缀} – 使用提供的参数构造一个对象——验证、转换和构建。示例:LocalDateTime.from(...) or OffsetTime.from(...)
  • parse {类工厂方法前缀} – 通过解析提供的 CharSequence 参数获得对象。示例:LocalDate.parse(...) or OffsetDateTime.parse(...)
  • format {对象方法前缀} – 使用给定的时间格式参数格式化对象。示例:localDate.format(formatter)
  • get {对象方法前缀} – 返回目标时间对象的部分状态。示例:localDate.getDayOfWeek()
  • is {对象方法前缀} – 查询目标时间对象的部分状态。示例:localTime.isAfter(...)
  • with {对象方法前缀} – 对部分进行更改返回不可变时态对象的一个副本。示例:offsetTime.withHour(...)
  • plus {对象方法前缀} – 返回具有添加时间的时间对象的副本。示例:localDate.plusWeeks(...)
  • minus {对象方法前缀} – 返回时间对象减去时间的副本。示例:localTime.minusSeconds(...)
  • to {对象方法前缀} – 将时间对象转换为另一种类型的新时间对象。示例:localDateTime.toLocalDate(...)
  • at {对象方法前缀} – 使用提供的参数将时间对象组合成一个新的时间对象 。示例:localDate.atTime(...)

六、译者说

大家好,我是如梦技术 L.cmMica 作者感谢一起参与翻译的 张亚东JustAuthJap 作者)、李寻欢Pig 团队)。

这篇文章躺在译文列表里有一年多了,眼看 Java17 即将发布,然而大部分同学对 Java8 时间仅仅掌握了个皮毛,故翻译出来,希望对大家有所帮助。

另外欢迎关注我们 JAVA架构日记,我们会定期整理、翻译业内文章和梳理热门软件更新。另外我们团队开源有 PigSpringBladeAvueJustAuthIJPay Mica 等热门项目,欢迎 star!!!

浏览 37
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报