JDK8 新特性:新时间日期API
本文目录:
前言
在 JDK8 之前,我们经常使用到的时间API包括(Date、Calendar),Date 与字符串之间的转换使用 SimpleDateFormat 进行转换(parse()、format() 方法),然而 SimpleDateFormat 不是线程安全的。在设计上也是存在一些缺陷的,比如有两个 Date 类,一个在 java.util 包中,一个在 java.sql 包中。
在JDK8 中,引入了一套全新的时间日期API,这套 API 在设计上比较合理,使用时间操作也变得更加方便。并且支持多线程安全操作。
1.旧版日期时间API存在的问题
1.设计很差:在 java.util 和 java.sql 的包中都有日期类。java.util.Date 同时包含日期和时间,而java.sql.Date仅包含日期,此外用于格式化和解析的类又在 java.text 包中定义;
2.非线程安全:java.util.Date 是非线程安全的,所有的日期类都是可变的,这是 java 日期类最大的问题之一;
3.时区处理麻烦:日期类并不提供国际化,没有时区支持。因此 java 引入了 java.util.Calendar 和 java.util.TimeZone 类,但他们同样存在上述所有的问题
-
/**
-
* TODO JDK8之前日期存在的问题
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 11:28
-
*/
-
public class DateDemo01 {
-
-
public static void main(String[] args) {
-
//旧版日期时间 API 存在的问题
-
//1.设计不合理(JDK8 Date类已经 @Deprecated 注释,不推荐使用)
-
Date now =new Date(1985,9,23);
-
System.out.println(now);
-
-
//2.时间格式化和解析是线程不安全的
-
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
-
for (int i = 0; i < 50; i++) {
-
new Thread(()->{
-
try {
-
Date date = sdf.parse("2019-09-09");
-
System.out.println("date:"+date);
-
} catch (ParseException e) {
-
e.printStackTrace();
-
}
-
}).start();
-
}
-
}
-
}
多线程测试结果:(会有日期格式化错误的,还有直接报错的,说明线程是不安全)
-
date:Tue Jun 09 00:00:00 CST 2026
-
date:Tue Sep 09 00:00:00 CST 990
-
date:Tue Sep 09 00:00:00 CST 990
-
date:Tue Sep 09 00:00:00 CST 990
-
date:Sun Dec 01 00:00:00 CST 2019
-
date:Mon Sep 09 00:00:00 CST 2019(这个才是正确的)
-
date:Mon Sep 09 00:00:00 CST 2019
-
date:Mon Sep 09 00:00:00 CST 2019
-
Exception in thread "Thread-35" Exception in thread "Thread-37" java.lang.NumberFormatException: For input string: "1909E.21909"
-
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
-
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
-
at java.lang.Double.parseDouble(Double.java:538)
2.新日期时间 API 介绍
JDK8 中增加了一套全新的日期时间 API,这套 API 设计合理,是线程安全的。新的日期及时间 API 位于 java.time 包下,如下是一些该包下的关键类:
- LocalDate:表示日期,包含:年月日。格式为:2020-01-13
- LocalTime:表示时间,包含:时分秒。格式为:16:39:09.307
- LocalDateTime:表示日期时间,包含:年月日 时分秒。格式为:2020-01-13T16:40:59.138
- DateTimeFormatter:日期时间格式化类
- Instant:时间戳类
- Duration:用于计算 2 个时间(LocalTime,时分秒)之间的差距
- Period:用于计算 2 个日期(LocalDate,年月日)之间的差距
- ZonedDateTime:包含时区的时间
Java 中使用的历法是 ISO-8601 日历系统,他是世界民用历法,也就是我们所说的公里。平年有365天,闰年是366天。此外 Java8 还提供了 4 套其他历法,分别是:
- ThaiBuddhistDate:泰国佛教历
- MinguoDate:中华民国历
- JapaneseDate:日本历
- HijrahDate:伊斯兰历
3.用法介绍
1.JDK8 日期和时间类
LocalDate、LocalTime、LocalDateTime类的实例是不可变的对象,分别表示使用 ISO-8601 日历系统的日期、时间、日期和时间。他们提供了简单的日期或时间,并不包含当前的时间信息,也不包含与时区相关的信息。
对日期时间的修改,就是对已经存在的 LocalDate对象,根据需求创建它的修改版,最简单的方式是使用 withAttribute() 方法。withAttribute()方法会创建对象的一个副本,并按照需要修改它的属性。
以下所有方法都返回了一个修改属性的对象,它们并不会影响原来的日期对象。(即:修改后的日期与原来的日期不是一个对象,原日期不受影响)
-
/**
-
* TODO 时间日期类
-
* LocalDate、LocalTime、LocalDateTime
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 13:42
-
*/
-
public class DateDemo02 {
-
-
/**
-
* LocalDate 日期类(年月日)
-
*/
-
@Test
-
public void testLocalDate() {
-
//获取当前日期
-
LocalDate now = LocalDate.now();
-
System.out.println(now);
-
//指定日期 LocalDate.of(year,month,day)
-
LocalDate date = LocalDate.of(2008, 8, 8);
-
System.out.println(date);
-
//获取年
-
System.out.println("年:" + date.getYear());
-
//获取月(英文)
-
System.out.println("月(英文):" + date.getMonth());
-
//获取月(阿拉伯数字)
-
System.out.println("月(数字):" + date.getMonthValue());
-
//获取日
-
System.out.println("日:" + date.getDayOfMonth());
-
//是否是闰年
-
System.out.println("是否是闰年:" + date.isLeapYear());
-
//...其他方法,自行研究
-
}
-
-
/**
-
* LocalDate 时间类(时分秒)
-
*/
-
@Test
-
public void testLocalTime() {
-
//获取当前时间
-
LocalTime now = LocalTime.now();
-
System.out.println(now);
-
//指定日期 LocalTime.of(hour,minute,second)
-
LocalTime date = LocalTime.of(13, 26, 39);
-
System.out.println(date);
-
//获取时
-
System.out.println(date.getHour());
-
//获取分
-
System.out.println(date.getMinute());
-
//获取秒
-
System.out.println(date.getSecond());
-
//获取纳秒
-
System.out.println(now.getNano());
-
//...其他方法,自行研究
-
-
}
-
-
/**
-
* LocalDateTime 日期时间类(年月日 时分秒)
-
*/
-
@Test
-
public void testLocalDateTime() {
-
//LocalDateTime: LocalDate + LocalTime,有年月日 时分秒
-
LocalDateTime now = LocalDateTime.now();
-
System.out.println("当前日期时间:"+now);
-
//指定日期时间 LocalDateTime.of(year,month,day,hour,minute,second)
-
LocalDateTime date = LocalDateTime.of(2018, 7, 23, 18, 59, 31);
-
System.out.println(date);
-
//获取年
-
System.out.println(date.getYear());
-
//获取月
-
System.out.println(date.getMonth());
-
//获取日
-
System.out.println(date.getDayOfMonth());
-
//获取时
-
System.out.println(date.getHour());
-
//获取分
-
System.out.println(date.getMinute());
-
//获取秒
-
System.out.println(date.getSecond());
-
//...其他方法,自行研究
-
}
-
-
/**
-
* 修改时间
-
*/
-
@Test
-
public void modifyTime() {
-
//以LocalDateTime为例(LocalDate、LocalTime与此类似)
-
LocalDateTime now = LocalDateTime.now();
-
//修改年[修改时间(不是JDK8之前的setXXX(),而是使用withXXX())]
-
System.out.println("修改年后:" + now.withYear(9102));
-
//增加年(减使用 minusYear()方法)
-
System.out.println("+2年后:" + now.plusYears(2));
-
//增加日(减使用 minusDays()方法)
-
System.out.println("47天后:" + now.plusDays(47));
-
//...其他方法,自行研究
-
}
-
-
/**
-
* 时间比较
-
*/
-
@Test
-
public void compareTime() {
-
//以LocalDateTime为例(LocalDate、LocalTime与此类似)
-
//时间1
-
LocalDateTime now = LocalDateTime.now();
-
//时间2
-
LocalDateTime dateTime = LocalDateTime.of(2018, 7, 12, 13, 28, 51);
-
//判断前面日期是否在后面日期后
-
System.out.println("A时间是否晚于B时间:" + now.isAfter(dateTime));
-
//判断前面日期是否在后面日期前
-
System.out.println("A时间是否早于B时间:" + now.isBefore(dateTime));
-
//判断两个日期时间是否相等
-
System.out.println("两个时间是否相等:" + now.isEqual(dateTime));
-
//...其他方法,自行研究
-
}
-
}
2.JDK8 日期时间格式化与解析
-
/**
-
* TODO 日期时间格式化 + 解析 + 多线程执行(安全)
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 14:12
-
*/
-
public class DateDemo03 {
-
-
@Test
-
public void dateFormat(){
-
LocalDateTime now = LocalDateTime.now();
-
-
//格式化
-
//使用JDK自带的时间格式:ISO_DATE_TIME(默认提供了很多格式,请自行查看)
-
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
-
String format = now.format(dtf);
-
System.out.println("format="+format);
-
-
//指定时间格式(ofPattern()方法)
-
DateTimeFormatter dtf1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
-
String format1 = now.format(dtf1);
-
System.out.println(format1);
-
-
//解析(parse()方法)
-
LocalDateTime parse = LocalDateTime.parse(format1, dtf1);
-
System.out.println("parse="+parse);
-
-
/**
-
* 多线程执行(验证线程安全性)
-
* 1.返回结果正确 2.不抛异常
-
*/
-
for (int i = 0; i < 50; i++) {
-
new Thread(()->{
-
LocalDateTime parse1 = LocalDateTime.parse(format1, dtf1);
-
System.out.println("parse="+parse1);
-
}).start();
-
}
-
}
-
}
3.JDK8 Instant 类
Instant 类,就是时间戳,内部保存了从1970年1月1日 00:00:00以来的秒和纳秒。
-
/**
-
* TODO JDK8的 Instant类(时间戳)
-
* (主要不是面向用户使用)
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 14:31
-
*/
-
public class DateDemo04 {
-
-
@Test
-
public void Instant(){
-
//Instant
-
// 内部保存了秒和纳秒,一般不是给用户使用的,而是方便程序做一些统计的(比如:统计方法耗时)
-
Instant now = Instant.now();
-
System.out.println("当前时间戳:"+now);//2020-01-13T06:48:46.267Z
-
//Instant类 并没有修改年月日等操作.因为 Instant 本来就不是给用户使用的
-
//Instant类:对 秒、纳秒等操作方便
-
Instant plus = now.plusSeconds(20);
-
System.out.println("+20秒后:"+plus);
-
-
Instant minus = now.minusSeconds(20);
-
System.out.println("-20秒后:"+minus);
-
-
//获取秒、毫秒、纳秒
-
long second = now.getEpochSecond();
-
System.out.println("秒:"+second);
-
int nano = now.getNano();
-
System.out.println("纳秒:"+nano);
-
//...其他方法,自行研究
-
}
-
}
4.JDK8 计算日期时间差类
Duration/Period 类:主要用来计算日期时间差
- Duration:用于计算 2 个时间(LocalTime,时分秒)的差值
- Period:用于计算 2 个 日期(LocalDate,年月日)的差值
-
/**
-
* TODO JDK8 计算日期时间差值
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 14:55
-
*/
-
public class DateDemo05 {
-
-
/**
-
* Duration类:计算时间的差值
-
*/
-
@Test
-
public void testTimeDiff(){
-
//时间1
-
LocalTime now = LocalTime.now();
-
//时间2
-
LocalTime dateTime = LocalTime.of(8, 15, 46);
-
//计算两个时间的差值
-
//计算规则:让第二个参数 减去 第一个参数(位置错误可能出现负数)
-
Duration duration = Duration.between(dateTime,now);
-
System.out.println("相差的天数:"+duration.toDays());
-
System.out.println("相差的小时数:"+duration.toHours());
-
System.out.println("相差的分钟数:"+duration.toMinutes());
-
System.out.println("相差的秒数:"+duration.toSeconds());//JDK 9+ 出现(JDK8会报错误)
-
System.out.println("相差的纳秒数:"+duration.toNanos());
-
//...其他方法,自行研究
-
}
-
-
/**
-
* Period类:计算日期的差值
-
*/
-
@Test
-
public void testDateDiff(){
-
//日期1
-
LocalDate now = LocalDate.now();
-
//日期2
-
LocalDate date = LocalDate.of(1999,5,29);
-
//计算两个日期的差值
-
//计算规则:让第二个参数 减去 第一个参数(位置错误可能出现负数)
-
Period period = Period.between(date,now);
-
System.out.println("相差的年:"+period.getYears());
-
System.out.println("相差的月:"+period.getMonths());
-
System.out.println("相差的日:"+period.getDays());
-
//...其他方法,自行研究
-
}
-
}
5.JDK8 日期时间调整器
有时我们可能需要获取,例如:"将日期调整到下一个月的第一天"等操作,此时我们可以通过时间调整器来进行操作。
- TemporalAdjuster:时间调整器
- TemporalAdjusters:工具类。该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现
-
/**
-
* TODO JDK8 时间调整器
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 15:10
-
*/
-
public class DateDemo06 {
-
-
/**
-
* TemporalAdjuster类:自定义调整时间
-
*/
-
@Test
-
public void timeCorrector(){
-
//将日期调整到"下一个月的第一天"操作
-
LocalDateTime now = LocalDateTime.now();
-
//参数:TemporalAdjuster adjuster。TemporalAdjuster是一个接口,里面只有 Temporal adjustInto(Temporal temporal); 这一个方法,支持接入 lambda 表达式
-
//此处 Temporal 就是指时间(包括 LocalDate、LocalTime、LocalDateTime 都是继承自该类。继承关系:如下图所示)
-
TemporalAdjuster adjuster = ( Temporal temporal)->{
-
LocalDateTime dateTime = (LocalDateTime)temporal;
-
return dateTime.plusMonths(1).withDayOfMonth(1);//下一个月第一天
-
};
-
LocalDateTime newDateTime = now.with(adjuster);
-
System.out.println("下个月第一天:"+newDateTime);
-
}
-
-
/**
-
* TemporalAdjusters工具类:使用JDK提供的时间调整器
-
*/
-
@Test
-
public void JDKTimeCorrector(){
-
//JDK中自带了很多时间调整器,其他调整器请自行查看
-
//使用 TemporalAdjusters 工具类
-
//TemporalAdjusters.firstDayOfNextYear()--->根据内容可知:下一年第一天
-
TemporalAdjuster temporalAdjuster = TemporalAdjusters.firstDayOfNextYear();
-
-
LocalDateTime now = LocalDateTime.now();
-
LocalDateTime newDateTime = now.with(temporalAdjuster);
-
System.out.println("下个月第一天:"+newDateTime);
-
}
-
}
附:继承关系(LocalDate、LocalTime、LocalDateTime、Temporal类)

6.JDK8 设置日期时间的时区
JDK8 中加入了对时区的支持。LocalDate、LocalTime、LocalDateTime 是不带时区的,带时区的日期时间类分别为:ZonedDate、ZonedTime、ZonedDateTime类。
其中每个时区都有对应着的 ID,ID的格式为"区域/城市",例如:Asia/Shanghai 等。
ZoneId类:该类中包含了所有的时区信息。
-
/**
-
* TODO JDK8设置时区(设置日期时间的时区)
-
*
-
* @author liuzebiao
-
* @Date 2020-1-13 15:43
-
*/
-
public class DateDemo07 {
-
-
/**
-
* 获取时区ID
-
*/
-
@Test
-
public void getZoneIds(){
-
//1.获取所有的时区ID
-
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
-
zoneIds.forEach(System.out::println);//返回600来个时区
-
}
-
-
/**
-
* 不带时区 Vs 带时区的日期时间
-
*/
-
@Test
-
public void ZonedDemo(){
-
//2.操作带时区的类
-
//不带时间,获取计算机的当前时间
-
LocalDateTime now = LocalDateTime.now();
-
System.out.println("now:"+now);
-
-
//中国使用的是东八区的时间,比标准时间早8个小时
-
//操作带时间的类
-
ZonedDateTime zdt = ZonedDateTime.now(Clock.systemUTC());//创建出来的时间是世界标准时间
-
System.out.println("世界标准时间:"+zdt);
-
}
-
-
/**
-
* 本地时间
-
*/
-
@Test
-
public void localTime(){
-
//now():使用计算机的默认的时区,创建日期时间
-
ZonedDateTime now = ZonedDateTime.now();
-
System.out.println("本地时间:"+now);//本地时间:2020-01-13T15:52:43.633+08:00[Asia/Shanghai]
-
}
-
-
/**
-
* 使用指定的时区来创建时间
-
*/
-
@Test
-
public void ZoneTime(){
-
-
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
-
System.out.println("设置指定时间:"+now);//设置指定时间:2020-01-13T02:56:24.776-05:00[America/New_York]
-
}
-
-
/**
-
* 修改时区
-
*/
-
@Test
-
public void modifyZone(){
-
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/New_York"));
-
-
//withZoneSameInstant():既更改时区,也更改时间
-
ZonedDateTime modifyTime = now.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
-
System.out.println("修改时区后的时间:"+modifyTime);
-
-
//withZoneSameLocal():只更改时区,不更改时间
-
ZonedDateTime modifyTime2 = now.withZoneSameLocal(ZoneId.of("Asia/Shanghai"));
-
System.out.println("修改时区后的时间:"+modifyTime2);
-
}
-
//...其他方法,自行研究
-
}
JDK8 新特性:新时间日期API的更多相关文章
- java8新特性——时间日期API
传统的时间 API 存在线程安全的问题,在多线程开发中必须要上锁,所以 java8 现在为我们提供了一套全新的时间日期 API ,今天进来学习一下java8 的时间日期 API. 一.使用 Local ...
- Java8新特性(三)——Optional类、接口方法与新时间日期API
一.Optional容器类 这是一个可以为null的容器对象.如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象. 查看结构图可以看到有如下常用方法: of(T)—— ...
- JAVA8学习——新的时间日期API&Java8总结
JAVA8-时间日期API java8之前用过的时间日期类. Date Calendar SimpleDateFormat 有很多致命的问题. 1.没有时区概念 2.计算麻烦,实现困难 3.类是可变的 ...
- Java8新特性——新一套时间API的使用
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了.而Calendar并不比Date好多少.它们面临的问题是: 可变性: ...
- Java 8 新的时间日期 API
1. 概述 1.1 简介 Java 8 引入了一套全新的时间日期API,操作起来更简便.简单介绍下,LocalDate和LocalTime和LocalDateTime的使用: java.util.Da ...
- Java 8新特性(Lambda,Stream API)
由于最近总监要求学习Java 8的一些知识,就去网上找了 一套教程来学习学习,将学习结果做一个小的总结记录,方便以后使用: 1.Java 8的优点 2.Lambda表达式优点 2.1Lambda实例 ...
- Java 8 的时间日期 API
上一篇文章『Java 的时间日期 API』中,我们学习了由 Date.Calendar,DateFormat 等组成的「传统时间日期 API」,但是传统的处理接口设计并不是很友好,不易使用.终于,Ja ...
- Atitit.mysql 5.0 5.5 5.6 5.7 新特性 新功能
Atitit.mysql 5.0 5.5 5.6 5.7 新特性 新功能 1. MySQL 5.6 5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 ...
- Atitit. visual studio vs2003 vs2005 vs2008 VS2010 vs2012 vs2015新特性 新功能.doc
Atitit. visual studio vs2003 vs2005 vs2008 VS2010 vs2012 vs2015新特性 新功能.doc 1.1. Visual Studio2 1.2. ...
- Atitit.mysql 5.0 5.5 5.6 5.7 新特性 新功能
Atitit.mysql 5.0 5.5 5.6 5.7 新特性 新功能 1. MySQL 5.6 5 大新特性1 1.1. 优化器的改进1 1.2. InnoDB 改进1 1.3. 使用 ...
随机推荐
- vue导出Excel表格各种样式
https://www.cnblogs.com/Awchao/p/14143385.html
- UFT VBScripts sharing
- AI把任意文章生成ppt的工具
讯飞智文 https://zhiwen.xfyun.cn/ 可以结合 https://notebooklm.google.com/ 把视频生成PPT
- Xamarin.Android 禁止横屏 /竖屏
this.RequestedOrientation = Android.Content.PM.ScreenOrientation.Portrait;//竖屏,禁止横屏 this.RequestedOr ...
- 前端开发系列078-Node篇之npm
本文输出Node中和包管理有关的基本内容,即npm的使用. 一.简单介绍 npm全称Node packAge Manager是Node官方提供的包管理工具,下面列出包管理工具的功能边界. > ❏ ...
- 简述FPS的计算方法
参考链接 cnblog 个人理解 单位时间内刷新的次数.
- ETL是什么?浅谈ETL对数据仓库的重要性
在当今数字化浪潮席卷全球的时代,存在着大量的数据孤岛,企业对于数据的重视程度达到了前所未有的高度.有效集成数据也成为企业决策分析过程的重中之重,ETL对数据集成发挥着至关重要的作用.那么,什么是ETL ...
- SciTech-AV-Audio-DAP(Digital Audio Processing)-Loudness Normalization(响度规范化): Perceived Loudness + RMS (Root Mean Square)
EBU: European Broadcasting Union Loudness Normalization Use the Loudness Normalization to change the ...
- babylon.js 学习笔记(5)
前面我们画的小房子,基本上都是用内置的标准形状组合而成,但并非所有对象都这么简单,今天我们来画一个小汽车,汽车由多个零件组成,控制这些零件的缩放.位置.旋转,如果每个都单独用代码来修改position ...
- shading-jdbc 4.1.1 + tk.mybatis + pagehelper 1.3.x +spring boot 2.x 使用注意事项
shading-jdbc 4.1.1 + tk.mybatis + pagehelper 1.3.x + spring boot 2.x 是一个很常用的组合,但在使用过程中可能会遇到一些小问题,记录 ...