Java 标准库 API 系列之 java.time 包

本贴最后更新于 329 天前,其中的信息可能已经渤澥桑田

一位 new Date() 大法好的老顽固的真香之旅。

new Date() 大法和 new SimpleDateFormat() 等 API 是从我 2018 年学习 Java 开始就一直在使用的处理日期和格式化日期的神器,直到几个月前我还是喜欢用他们,但是突然遇到一个比较复杂并且涉及用户分布在全球的报表需求时,我开始退坑了。。。

我开始使用 java.time 包下的 API,真香 ~~~

zs.gif

在 Java 8 之前,java.util.Datejava.util.Calendar 是用于表示日期和时间的类。但是这两个工具类 存在很多问题,例如:

  • DateCalender 是可变的,这意味着它不是线程安全的。
  • java.util.Date 的时间表示只能精确到毫秒,不能精确到更小的时间单位。
  • API 设计相对复杂且容易出错。
    • Calender 使用了许多常量和魔法值,不够直观。例如,月份从 0 开始计数,这与我们通常的习惯不同,容易导致错误。
    • Date 存储的时间是从 1970-01-01T00:00:00Z(即格林威治时间)开始经过的时间,但是它的 API 设计存在很多问题,例如 getYear() 方法返回的是从 1900 年开始经过的年数,导致其易于出现错误。

为了解决这些问题,Java 8 引入了新的日期时间 API(即 java.time 包)也就是这篇文章要介绍和推广的,其中的日期时间类是不可变的、线程安全的,并且支持更精确的时间单位。这些类包括:

  • LocalDate:表示日期(年月日)。
  • LocalTime:表示时间(小时分钟秒)。
  • LocalDateTime:表示日期和时间。
  • ZonedDateTime:表示带有时区信息的日期和时间。
  • Instant:表示从 1970-01-01T00:00:00Z(即格林威治时间)开始经过的时间,精确到纳秒。
  • Duration:表示时间段。
  • Period:表示日期段。

接下来我就一个一个的介绍这些 API 的使用,觉得有帮助的话可以点个赞哦!

Instant

这个类代表了一个精确的时间点。它的实例可以用于表示一个事件的发生时间,以便于在不同时区之间进行转换。示例代码如下:

Instant instant = Instant.now();

Date 也可以转换成 Instant,如下:

var instant = new Date().toInstant();

LocalDate

这个类代表了一个日期,不含有具体时间信息。它提供了一系列的静态工厂方法,可以根据年月日的值创建实例。示例代码如下:

LocalDate date = LocalDate.of(2023, 3, 21);

LocalTime

这个类代表了一个时间,不含有具体日期信息。它同样提供了一系列的静态工厂方法,可以根据时分秒的值创建实例。示例代码如下:

LocalTime time = LocalTime.of(12, 30);

LocalDateTime

这个类同时包含了日期和时间信息。可以通过合并 LocalDateLocalTime 的实例来创建 LocalDateTime 实例。示例代码如下:

LocalDateTime dateTime = LocalDateTime.of(2023, 3, 21, 12, 30);

也可以从 Date 转换成 LocalDateTime

var instant = new Date().toInstant();
var localDateTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();

ZoneDateTime

ZoneDateTimeLocalDateTime 的基础上加上了时区信息。也就是说,它可以使用 LocalDateTime 类中所有的方法和属性。这让我们在处理一些全球性的业务是可以如鱼得水。

ZonedDateTime 类中,我们可以通过 ZoneId 类来设置时区。ZoneId 是一个表示时区的类,它包含所有的时区信息,并且提供了多种获取时区的方法。以下是一些常用的 ZoneId 的用法:

// 通过时区ID获取一个时区对象
ZoneId zoneId = ZoneId.of("Asia/Shanghai");

// 获取默认时区对象
ZoneId defaultZoneId = ZoneId.systemDefault();

可以看到,我们可以通过指定时区 ID 来获取对应的时区对象,也可以使用 systemDefault() 方法获取当前默认的时区对象。

然后,我们可以使用 ZonedDateTime 类来表示具有时区信息的日期和时间。下面是一个创建 ZonedDateTime 实例的示例代码:

// 获取当前时间
LocalDateTime localDateTime = LocalDateTime.now();

// 使用指定时区将当前时间转换为带时区的日期时间
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);

Duration 和 Period

这两个类分别代表了时间段和日期段。Duration 可以精确表示秒和纳秒之间的时间差,而 Period 可以精确表示年、月、日之间的时间差。示例代码如下:

Duration duration = Duration.between(LocalTime.now(), LocalTime.of(18, 0));
Period period = Period.between(LocalDate.now(), LocalDate.of(2023, 3, 30));

DateTimeFormatter

这个类提供了一系列的静态方法,可以将日期和时间对象格式化为字符串,也可以将字符串解析为日期和时间对象。再也不用 new SimpleDateFormat() 了。

示例代码如下:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String strDateTime = dateTime.format(formatter);
LocalDateTime parsedDateTime = LocalDateTime.parse(strDateTime, formatter);

方便的 API

java.time 提供的这些工具类,出了明确的职责和优良的设计之外,还提供了非常方便好用的 API,简化我们对于日期的计算。

包括但不限于

var today = LocalDate.now();//今天的信息
var yesterday = today.minusDays(1) //昨天的信息
var tomorrow = today.plusDays(1) //明天的信息
var firstDayOfMoth = today.withDayOfMonth(1); //返回这个月的第一天 1-31
var yesterdayStartTime = yesterday.atStartOfDay() //获取昨天零点的LocalDateTime对象
var dayOfYear = today.getDayOfWeek() //获取今天是这周中的第几天
var dayOfYear = today.getDayOfMonth() //获取今天是这个月中的第几天
var dayOfYear = today.getDayOfYear() //获取今天是一年中的第几天
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3168 引用 • 8207 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...