Java8新特性之新日期时间库的使用教程

 更新时间:2020年12月16日 08:44  点击:2146

一、为什么引入新的日期时间库

Java对日期,日历及时间的处理一直以来都饱受诟病,尤其是它决定将java.util.Date定义为可修改的以及将SimpleDateFormat实现成非线程安全的。

关于这个新的时间日期库的最大的优点就在于它定义清楚了时间日期相关的一些概念,比方说,瞬时时间(Instant),持续时间(duration),日期(date),时间(time),时区(time-zone)以及时间段(Period)。同时它也借鉴了Joda库的一些优点,比如将人和机器对时间日期的理解区分开的。Java 8仍然延用了ISO的日历体系,并且与它的前辈们不同,java.time包中的类是不可变且线程安全的。

二、如何使用Java8的新日期和时间

首先认识下Java8新日期和时间的一些关键类:

类名 说明
Instant 代表时间戳
LocalDate 不包含具体时间的日期
LocalTime 不包含日期的时间
LocalDateTime 包含了日期及时间,没有时区信息
ZonedDateTime 包含时区的完整的日期时间,偏移量是以UTC/格林威治时间为基准的
DateTimeFormatter 日期解析和格式化工具类

接下来从几个示例中认识Java8新日期和时间的特别之处,很强大

在Java8中获取当前日期

Java 8中有一个叫LocalDate的类,它能用来表示今天的日期。这个类与java.util.Date略有不同,因为它只包含日期,没有时间。因此,如果你只需要表示日期而不包含时间,就可以使用它。

LocalDate today = LocalDate.now();
System.out.println("Today is : " + today);

输出结果:

Today is : 2020-12-13

从输出结果中可以看到,日期是格式化完了后再输出来的,不像之前的Date类那样,打印出来的数据都是未经格式化的,不便于阅读。

在Java8中获取当前的年月日

LocalDate类中提供了一些很方便的方法可以用于提取出年月日以及其它的日期属性。使用这些方法,你可以获取到任何你所需要的日期属性,而不再需要使用java.util.Calendar这样的类

LocalDate today = LocalDate.now();
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.printf("Year : %d , Month : %d , day : %d \t %n", year, month, day);

输出结果:

Year : 2020 , Month : 12 , day : 13

在Java8中获取某个特定的日期

使用工厂方法LocalDate.of(),则可以创建出任意一个日期,它接受年月日的参数,然后返回一个等价的LocalDate实例。关于这个方法还有一个好消息就是它没有再犯之前API中的错,比方说,年只能从1900年开始,月必须从0开始,等等。这里的日期你写什么就是什么,比如说,下面这个例子中它代表的就是1月14日,没有什么隐藏逻辑

LocalDate today = LocalDate.of(2020, 12, 13);
System.out.println("Today is : " + today);

输出结果:

Today is : 2020-12-13

在Java8中检查两个日期是否相等

LocalDate重写了equals方法来进行日期的比较

LocalDate today = LocalDate.now();
LocalDate date = LocalDate.of(2014, 01, 14); 
if(date.equals(today)){ 
  System.out.printf("Today %s and date %s are same date %n", today, date); 
} 

输出结果:

Today 2020-12-13 and date 2020-12-13 are same date

在Java8中检查重复事件

使用MonthDay类。这个类由月日组合,不包含年信息,也就是说你可以用它来代表每年重复出现的一些日子。当然也有一些别的组合,比如说YearMonth类。它和新的时间日期库中的其它类一样也都是不可变且线程安全的,并且它还是一个值类(value class)

LocalDate today = LocalDate.now();
LocalDate dateOfBirth = LocalDate.of(2020, 12, 13);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(), dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(today);
if (currentMonthDay.equals(birthday)) {
System.out.println("Oh, today is your birthday");
} else {
System.out.println("Sorry, today is not your birthday");
}

输出结果:

Oh, today is your birthday

在Java8中获取当前时间

使用LocalTime的类,它是没有日期的时间,与LocalDate是近亲。这里你也可以用静态工厂方法now()来获取当前时间。默认的格式是hh:mm:ss:nnn,这里的nnn是纳秒

LocalTime time = LocalTime.now();
System.out.println("local time now : " + time);

输出结果:

local time now : 13:44:48.255

在Java8中增加小时数

Java 8不仅提供了不可变且线程安全的类,它还提供了一些更方便的方法譬如plusHours()来替换原来的add()方法。顺便说一下,这些方法返回的是一个新的LocalTime实例的引用,因为LocalTime是不可变的,可别忘了存储好这个新的引用。

LocalTime time = LocalTime.now();
LocalTime newTime = time.plusHours(2);
System.out.println("Time after 2 hours : " + newTime);

输出结果:

Time after 2 hours : 15:47:00.787

在Java8中获取1周后的日期

LocalDate是用来表示无时间的日期的,它有一个plus()方法可以用来增加日,星期,或者月,ChronoUnit则用来表示这个时间单位。由于LocalDate也是不可变的,因此任何修改操作都会返回一个新的实例,因此别忘了保存起来。

LocalDate today = LocalDate.now();
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);
System.out.println("Today is : " + today);
System.out.println("Date after 1 week : " + nextWeek);

输出结果:

Today is : 2020-12-13
Date after 1 week : 2020-12-20

在Java8中获取一年前后的日期

使用LocalDate的plus()方法来给日期增加日,周或者月,现在我们来学习下如何用minus()方法来找出一年前的那天。

LocalDate today = LocalDate.now();
LocalDate previousYear = today.minus(1, ChronoUnit.YEARS);
System.out.println("Date before 1 year : " + previousYear);
LocalDate nextYear = today.plus(1, ChronoUnit.YEARS);
System.out.println("Date after 1 year : " + nextYear);

输出结果:

Date before 1 year : 2019-12-13
Date after 1 year : 2021-12-13

在Java8中使用时钟

Java 8中自带了一个Clock类,你可以用它来获取某个时区下当前的瞬时时间,日期或者时间。可以用Clock来替代System.currentTimeInMillis()与 TimeZone.getDefault()方法,如果你需要对不同时区的日期进行处理的话这是相当方便的。

// Returns the current time based on your system clock and set to UTC.
Clock clock1 = Clock.systemUTC();
System.out.println("Clock : " + LocalDate.now(clock1));

// Returns time based on system clock zone Clock defaultClock = 
Clock clock2 = Clock.systemDefaultZone();
System.out.println("Clock : " + LocalDate.now(clock2));

输出结果:

Clock : 2020-12-13
Clock : 2020-12-13

在Java8中判断一个日期在某个日期的前后

在Java 8中,LocalDate类有一个isBefore()和isAfter()方法可以用来比较两个日期。如果调用方法的那个日期比给定的日期要早的话,isBefore()方法会返回true。

LocalDate today = LocalDate.now();
LocalDate tomorrow = LocalDate.of(2020, 12, 14);
if (tomorrow.isAfter(today)) {
  System.out.println("Tomorrow comes after today");
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if (yesterday.isBefore(today)) {
  System.out.println("Yesterday is day before today");
}

输出结果:

Tomorrow comes after today
Yesterday is day before today

在Java8中处理不同的时区

Java 8不仅将日期和时间进行了分离,同时还有时区。现在已经有好几组与时区相关的类了,比如ZonId代表的是某个特定的时区,而ZonedDateTime代表的是带时区的时间。

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localDateTime, ZoneId.of("America/New_York"));
System.out.println("Current date and time in a particular timezone : " + dateAndTimeInNewYork);

输出结果:

Current date and time in a particular timezone : 2020-12-13T14:40:44.664-05:00[America/New_York]

在Java8中表示固定的日期

YearMonth又是另一个组合,它代表的是像信用卡还款日,定期存款到期日,options到期日这类的日期。你可以用这个类来找出那个月有多少天,lengthOfMonth()这个方法返回的是这个YearMonth实例有多少天,这对于检查2月到底是28天还是29天可是非常有用的。

YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2020, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);

输出结果:

Days in month year 2020-12: 31
Your credit card expires on 2020-02

在Java8中检查闰年

LocalDate类有一个isLeapYear()的方法能够返回当前LocalDate对应的那年是否是闰年。

LocalDate today = LocalDate.now();
if (today.isLeapYear()) {
System.out.println("This year is Leap year");
} else {
System.out.println("2020 is not a Leap year");
}

输出结果:

This year is Leap year

在Java8中判断两个日期之间包含多少天/月

一个常见的任务就是计算两个给定的日期之间包含多少天,多少周或者多少年。你可以用java.time.Period类来完成这个功能。

LocalDate today = LocalDate.now();
LocalDate java8Release = LocalDate.of(2021, Month.JANUARY, 13);
Period periodToNextJavaRelease = Period.between(today, java8Release);
System.out.println("Months left between today and Java 8 release : " + periodToNextJavaRelease.getMonths());

输出结果:

Months left between today and Java 8 release : 1

在Java8中获取当前时间戳

Instant类有一个静态的工厂方法now()可以返回当前时间戳

Instant timestamp = Instant.now();
System.out.println("instant : " + timestamp);

输出结果:

instant : 2020-12-13T07:30:55.877Z

在Java8中使用预定义的格式器来对日期进行解析/格式化

在Java 8之前,时间日期的格式化可是个技术活,我们的好伙伴SimpleDateFormat并不是线程安全的,而如果用作本地变量来格式化的话又显得有些笨重。多亏了线程本地变量,这使得它在多线程环境下也算有了用武之地。这次它引入了一个全新的线程安全的日期与时间格式器。它还自带了一些预定义好的格式器,包含了常用的日期格式。

String date = "20201213";
LocalDate formatted = LocalDate.parse(date, DateTimeFormatter.BASIC_ISO_DATE);
System.out.printf("Date generated from String %s is %s %n", date, formatted);

输出结果:

Date generated from String 20201213 is 2020-12-13

在Java8中使用自定义的格式器来解析日期

在DateTimeFormatter的ofPattern静态方法()传入任何的模式,它会返回一个实例,这个模式的字面量与前例中是相同的。比如说M还是代表月,而m仍是分。无效的模式会抛出DateTimeParseException异常

String goodFriday = "12 13 2020";
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM dd yyyy");
LocalDate holiday = LocalDate.parse(goodFriday, formatter);
System.out.printf("Successfully parsed String %s, date is %s%n", goodFriday, holiday);
} catch (DateTimeParseException ex) {
ex.printStackTrace();
}

输出结果:

Successfully parsed String 12 13 2020, date is 2020-12-13

在Java8中对日期进行格式化,转换成字符串

使用DateTimeFormatter类的实例,调用它的format()方法。这个方法会返回一个代表当前日期的字符串,对应的模式就是传入的DateTimeFormatter实例中所定义好的。

LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mm a");
String landing = localDateTime.format(format);
System.out.printf("Arriving at : %s %n", landing);

输出结果:

Arriving at : 十二月 13 2020 04:13 下午

三、总结

  • Java 8中新的时间与日期API中的所有类都是不可变且线程安全的,这与之前的Date与Calendar API中的恰好相反,那里面像java.util.Date以及SimpleDateFormat这些关键的类都不是线程安全的。
  • 新的时间与日期API中很重要的一点是它定义清楚了基本的时间与日期的概念,比方说,瞬时时间,持续时间,日期,时间,时区以及时间段。它们都是基于ISO日历体系的。
  • Java8新的API能胜任任何与时间日期相关的任务。

到此这篇关于Java8新特性之新日期时间库使用的文章就介绍到这了,更多相关Java8新日期时间库内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

[!--infotagslink--]

相关文章

  • Java8 实现stream将对象集合list中抽取属性集合转化为map或list

    这篇文章主要介绍了Java8 实现stream将对象集合list中抽取属性集合转化为map或list的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • java8如何用Stream查List对象某属性是否有重复

    这篇文章主要介绍了java8如何用Stream查List对象某属性是否有重复的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-09-11
  • java8中的Collectors.groupingBy用法详解

    这篇文章主要介绍了java8中的Collectors.groupingBy用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-17
  • Java8处理List的双层循环问题

    这篇文章主要介绍了Java8处理List的双层循环问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-19
  • 浅谈Java8 的foreach跳出循环break/return

    这篇文章主要介绍了Java8 的foreach跳出循环break/return,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-07-28
  • Java8 使用流抽取List<T>集合中T的某个属性操作

    这篇文章主要介绍了Java8 使用流抽取List<T>集合中T的某个属性操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • java8时间 yyyyMMddHHmmss格式转为日期的代码

    这篇文章主要介绍了java8时间 yyyyMMddHHmmss格式转为日期的代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-17
  • Java8之Stream流代替For循环操作

    这篇文章主要介绍了Java8之Stream流代替For循环操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-19
  • Java8 自定义CompletableFuture的原理解析

    这篇文章主要介绍了Java8 自定义CompletableFuture的原理解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-11-04
  • Java8中Stream的一些神操作

    Stream是Java8中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作,这篇文章主要给大家介绍了Java8中Stream的一些神操作,需要的朋友可以参考下...2021-11-02
  • java8 streamList转换使用详解

    这篇文章主要介绍了java8 streamList转换使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-16
  • Java8通过Function获取字段名的方法(获取实体类的字段名称)

    Java8通过Function获取字段名。不用再硬编码,效果类似于mybatis-plus的LambdaQueryWrapper,对Java8通过Function获取字段名相关知识感兴趣的朋友一起看看吧...2021-09-29
  • java8 实现提取集合对象的每个属性

    这篇文章主要介绍了java8 实现提取集合对象的每个属性方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • JAVA8妙用Optional解决判断Null为空的问题方法

    本文主要介绍了JAVA8妙用Optional解决判断Null为空的问题方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-10-22
  • Java8优雅的字符串拼接工具类StringJoiner实例代码

    这篇文章主要给大家介绍了关于Java8优雅的字符串拼接工具类StringJoiner的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-28
  • java8新特性 获取list某一列的操作

    这篇文章主要介绍了java8新特性 获取list某一列的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-05
  • java8新特性之stream流中reduce()求和知识总结

    今天带大家回顾Java8的新特性,文中对stream流中reduce()求和的相关知识作了详细的介绍,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下...2021-05-25
  • java8 Stream list to Map key 重复 value合并到Collectio的操作

    这篇文章主要介绍了java8 Stream list to Map key 重复 value合并到Collectio的操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2021-06-10
  • Java8新特性之新日期时间库的使用教程

    这篇文章主要给大家介绍了关于Java8新特性之新日期时间库使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-16
  • 详解Java8合并两个Map中元素的正确姿势

    这篇文章主要介绍了详解Java8合并两个Map中元素的正确姿势,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-09-02