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

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 下午 

三、总结

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

Java8新特性探索之新日期时间库的更多相关文章

  1. Atitit python3.0 3.3 3.5 3.6 新特性 Python2.7新特性1Python 3_x 新特性1python3.4新特性1python3.5新特性1值得关注的新特性1Pyth

    Atitit python3.0 3.3 3.5 3.6 新特性 Python2.7新特性1 Python 3_x 新特性1 python3.4新特性1 python3.5新特性1 值得关注的新特性1 ...

  2. 11g新特性与12c新特性

    1. 11g新特性概图 管理新特性> 开发新特性> 2. 12c 新特性概图

  3. Atitit.业务系统的新特性 开发平台 新特性的来源总结

    Atitit.业务系统的新特性 开发平台 新特性的来源总结 1.1. 语言新特性(java c# php js python lisp c++ oc swift ruby  go dart1 1.2. ...

  4. js非常强大的日历控件fullcalendar.js, 日期时间库: moment.js

    日历控件: https://fullcalendar.io/docs/ https://fullcalendar.io/docs/event_data/events_function/ https:/ ...

  5. Microsoft Dynamics AX 7 新特性探索 - Demo 部署(Part 1)

    Dynamics AX 7已经发布了一段时间了,我们知道这次微软为我们带来了许多令人激动的新特性.在这个系列里,Reinhard将揭开New Dynamics AX的神秘面纱,和大家一起探索这些新的特 ...

  6. Java8学习笔记(九)--日期/时间(Date Time)API指南

    Java 8日期/时间( Date/Time)API是开发人员最受追捧的变化之一,Java从一开始就没有对日期时间处理的一致性方法,因此日期/时间API也是除Java核心API以外另一项倍受欢迎的内容 ...

  7. Java 新特性(3) - JDK7 新特性

    http://www.ibm.com/developerworks/cn/java/j-lo-jdk7-1/ JSR292:支持动态类型语言(InvokeDynamic) 近 年来越来越多的基于 JV ...

  8. kubernetes1.4新特性:增加新的节点健康状况类型DiskPressure

    背景资料 在Kubernetes架构图中可以看到,节点(Node)是一个由管理节点委托运行任务的worker. 它能运行一个或多个Pods,节点(Node)提供了运行容器环境所需要的所有必要条件,在K ...

  9. 新特性AAtitti css3 新特性attilax总结titti css

    Atitti css3 新特性attilax总结 图片发光效果2 透明渐变效果2 文字描边2 背景拉伸2 CSS3 选择器(Selector)4 @Font-face 特性7 Word-wrap &a ...

随机推荐

  1. 使用python统计《三国演义》小说里人物出现次数前十名,并实现可视化。

    一.安装所需要的第三方库 jieba (jieba是优秀的中文分词第三分库) pyecharts (一个优秀的数据可视化库) <三国演义>.txt下载地址(提取码:kist ) 使用pyc ...

  2. 用FL Studio来给电子音乐混音的方法

    FL Studio也算是音乐人用的比较多的编曲.混音软件了,FL Studio的一大的特色就是电子音乐的制作.尤其是对混音的操作,混音是电音制作过程中一个非常重要的环节,非常重要. 混音是什么?混音的 ...

  3. jQuery 第三章 CSS操作

    .css() .attr() .prop() .css() 参数填法:如下所示 ↓  可填px 可不填,注意点:background-color  这类属性,需要填成 小驼峰式  background ...

  4. 图像分割必备知识点 | Unet详解 理论+ 代码

    文章转自:微信公众号[机器学习炼丹术].文章转载或者交流联系作者微信:cyx645016617 喜欢的话可以参与文中的讨论.在文章末尾点赞.在看点一下呗. 0 概述 语义分割(Semantic Seg ...

  5. Flask端点概念

    Flask要点理解 路由端点 通常,我们使用app.route()装饰器将视图函数注册为路由.如果不使用该装饰器,也可以采用app.add_url_rule(rule, endpoint, view_ ...

  6. leetcode 练习--反转链表

    最近开始学习数据结构和算法的学习,也自然开始在 leetcode 上练习,所以每周大概会分享做过的leetcode 练习,尽量做到每天更新一道题目. 作为 leetcode 练习笔记的第一道题目,选择 ...

  7. C++stl简单使用

    1 //1.sort函数排序 2 /* 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; ...

  8. [BUGCASE]层叠上下文和z-index属性使用不当引发的文本被遮挡的问题

    一.问题描述 在一个fixed-data-table(一个React组件)制作的表格中,需要给表头的字段一个提示的特效,所以做了一个提示层 这个提示层被固定(拖动表格的水平滚动条时固定)的表格列遮住 ...

  9. IEEE浮点数标准

    IEEE浮点数标准 阅读笔记:Computer System : A Programmmer's Perspective 基本概念 IEEE浮点数标准采用 \[V=(-1)^s\times M\tim ...

  10. CentOS7系统tab命令补全

    在新安装的CentOS7系统中,如果没有安装命令补全的话,在systemctl管理服务的时候就没法用tab来自动补全,因此在安装完系统后,我们要再安装命令补全这个软件: yum -y install ...