Java8新特性探索之新日期时间库
一、为什么引入新的日期时间库
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新特性探索之新日期时间库的更多相关文章
- 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 ...
- 11g新特性与12c新特性
1. 11g新特性概图 管理新特性> 开发新特性> 2. 12c 新特性概图
- Atitit.业务系统的新特性 开发平台 新特性的来源总结
Atitit.业务系统的新特性 开发平台 新特性的来源总结 1.1. 语言新特性(java c# php js python lisp c++ oc swift ruby go dart1 1.2. ...
- js非常强大的日历控件fullcalendar.js, 日期时间库: moment.js
日历控件: https://fullcalendar.io/docs/ https://fullcalendar.io/docs/event_data/events_function/ https:/ ...
- Microsoft Dynamics AX 7 新特性探索 - Demo 部署(Part 1)
Dynamics AX 7已经发布了一段时间了,我们知道这次微软为我们带来了许多令人激动的新特性.在这个系列里,Reinhard将揭开New Dynamics AX的神秘面纱,和大家一起探索这些新的特 ...
- Java8学习笔记(九)--日期/时间(Date Time)API指南
Java 8日期/时间( Date/Time)API是开发人员最受追捧的变化之一,Java从一开始就没有对日期时间处理的一致性方法,因此日期/时间API也是除Java核心API以外另一项倍受欢迎的内容 ...
- Java 新特性(3) - JDK7 新特性
http://www.ibm.com/developerworks/cn/java/j-lo-jdk7-1/ JSR292:支持动态类型语言(InvokeDynamic) 近 年来越来越多的基于 JV ...
- kubernetes1.4新特性:增加新的节点健康状况类型DiskPressure
背景资料 在Kubernetes架构图中可以看到,节点(Node)是一个由管理节点委托运行任务的worker. 它能运行一个或多个Pods,节点(Node)提供了运行容器环境所需要的所有必要条件,在K ...
- 新特性AAtitti css3 新特性attilax总结titti css
Atitti css3 新特性attilax总结 图片发光效果2 透明渐变效果2 文字描边2 背景拉伸2 CSS3 选择器(Selector)4 @Font-face 特性7 Word-wrap &a ...
随机推荐
- Linux Shell操作 执行C代码显示当前路径
在unix系统下一切皆文件,文件夹是文件的一种.设备也会对应到相应的文件类型. 基础知识: . 代表当前路径 ..代表上级目录(父目录) / 在路径的最前边的时候代表树根.在路径中间的时候只不过是路径 ...
- Zabbix监控笔记
了解zabbix,有必要了聊一下监控系统相关内容 企业中常用的开源监视系统目前有 cacti.Nagios.Open-Falcon.zabbix.prometheus等 使用监控系统的目的在于 /1. ...
- 会声会影使用教程:剪辑Vlogo短视频
随着抖音.快手等视频分享软件的兴起,很多人已经开始尝试制作短视频分享.那么,对于视频制作新手来说,短视频的制作难度大吗?其实,只要选对了视频制作软件,视频制作将会变得相当简单. 在众多视频制作软件中, ...
- CDR魔镜插件是什么,有哪些功能?
CDR魔镜插件是一款功能强大的CorelDRAW插件,很多CDR用户很早直接就有接触,因其强大的功能性和快速运行的特点被广大用户所喜爱,没有繁琐的选项,无论新人小白,还是制图高手都能够很快的适应,实现 ...
- FL Studio里一起安装的ASIO4ALL有什么用?
在我们安装FL Studio时,正常情况下我们安装FL Studio时最多也就改改安装目录,其他的安装设置一般不会动,但看到FL安装的那些东西我们难道不会感到好奇吗?FL Studio安装包括FL S ...
- python菜鸟教程学习9:函数
函数的定义 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段.python提供了很多内建函数,但我们依然可以自己创建函数,叫做用户自定义函数. 自定义函数 你可以定义一个由自己想要功能 ...
- mycat分片及主从(二)
一.mycat分片规则 经过上一篇幅讲解,应该很清楚分片规则配置文件rule.xml位于$MYCAT_HOME/conf目录,它定义了所有拆分表的规则.在使用过程中可以灵活使用不同的分片算法,或者对同 ...
- Java基础教程——Object类
Object类 Object类是Java所有类类型的父类(或者说祖先类更合适) <Thinking in Java(Java编程思想)>的第一章名字就叫"everything i ...
- MySQL制作具有千万条测试数据的测试库
有时候需要制造一些测试的数据,以mysql官方给的测试库为基础,插入十万,百万或者千万条数据.利用一些函数和存储过程来完成. 官方给的测试库地址:https://github.com/datachar ...
- C# 9.0新特性详解系列之三:模块初始化器
1 背景动机 关于模块或者程序集初始化工作一直是C#的一个痛点,微软内部外部都有大量的报告反应很多客户一直被这个问题困扰,这还不算没有统计上的客户.那么解决这个问题,还有基于什么样的考虑呢? 在库加载 ...