JDK8--09:全新的时间API
在JDK8之前,时间有各种问题,最大的问题就是,我们使用的时间格式化类SimpleDateFormat不是线程安全的
为了更准确的说明SimpleDateFormat非线程安全,演示一个并发做时间格式化的操作
public void test() throws Exception{
//全新的时间API 都不是线程安全的
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
Callable<Date> call = new Callable<Date>() {
@Override
public Date call() throws Exception {
return simpleDateFormat.parse("");
}
};
ExecutorService newFixedThreadPool = Executors.newFixedThreadPool();
List<Future<Date>> list = new ArrayList<>();
for(int i=;i<;i++){
list.add(newFixedThreadPool.submit(call));
}
for (Future<Date> future : list){
log.info("============={}",future.get());
}
newFixedThreadPool.shutdown();
}
运行结果:

就是因为多个线程并发使用SimpleDateFormat,因此出现了异常,那么JDK8之前我们是如何保证SimpleDateFormat线程安全的呢?
在JDK8之前,我们使用ThreadLocal锁定SimpleDateFormat,来保证线程安全:
首先,创建一个使用TreadLocal锁定的SimpleDateFormat
public class DateFormatThreadLocal {
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>(){
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
public static Date convert(String source) throws Exception{
return df.get().parse(source);
}
}
其次,在做时间格式化时,使用该类中锁定的SimpleDateFormat对象
@Test
public void test2() throws Exception{
//全新的时间API 都不是线程安全的
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMdd"); Callable<LocalDate> call = new Callable<LocalDate>() {
@Override
public LocalDate call() throws Exception {
return LocalDate.parse("",dateTimeFormatter);
}
}; ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(); List<Future<LocalDate>> list = new ArrayList<>(); for(int i=;i<;i++){
list.add(newFixedThreadPool.submit(call));
} for (Future<LocalDate> future : list){
log.info("============={}",future.get());
} newFixedThreadPool.shutdown();
}
运行结果:

可以发现,程序运行正常,均做了格式化
那么在JDK8中,提供了全新的时间类,这些类都是线程安全的,可以在多线程并发时使用,无需担心线程安全问题,无需创建ThreadLocal锁定的格式化类
首先,介绍JDK8中新增的时间类 :LocalDate LocalTime LocalDateTime
1、时间对象创建
(1)可以使用now创建时间类,时间为当前时间
(2)可以使用of创建指定时间
//创建日期
//LocalDate LocalTime LocalDateTime
LocalDateTime ld = LocalDateTime.now();
log.info("LocalDateTime.now()=================={}", ld); LocalDateTime ld1 = LocalDateTime.of(,,,,,);
log.info("LocalDateTime=================={}", ld1);
2、日期运算:JDK8提供了plus*方法可以对日期进行运算操作
//日期运算 plus 加日期
LocalDateTime ld = LocalDateTime.now();
log.info("plusDays=================={}", ld.plusDays());
log.info("plusHours=================={}", ld.plusHours());
3、get返回值:JDK8提供了get*方法可以返回年份、月份、日期等
//get 返回值
LocalDateTime ld = LocalDateTime.now();
log.info("getMonthValue=================={}", ld.getMonthValue());
log.info("getDayOfMonth=================={}", ld.getDayOfMonth());
4、时间戳操作
上面提到的LocalDate、LocalTime、LocalDateTime输出的都是指定的时间格式,但是如果我们需要使用时间戳,就需要其他的方式处理,对于时间戳的操作如下:
(1)直接获取时间戳,此时获取的时间戳为UTC时间,即世界协调时间(世界标准时间,以北京时间为例,由于北京时间采取的是东八区时间,因此是标准时间+8个小时,即为北京时间)
(2)获取指定时区的时间戳
(3)转换为时间戳
(4)指定时间戳起始时间(1970-01-01 00:00:00)后多少时间的时间戳
//时间戳
Instant instant = Instant.now();//默认是UTC时间(世界协调时间)
log.info("时间戳===={}", instant);
//转换为东八区时间(北京时间)
OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours());
log.info("转换为东八区时间(北京时间)=={}", offsetDateTime);
//转换为时间戳
long toEpochMilli = instant.toEpochMilli();
log.info("时间戳=={}", toEpochMilli); //改变时间 距离时间戳的时间 1970-01-01 00:00:00
Instant instant1 = Instant.ofEpochSecond(*);
log.info("距离时间戳的时间=={}", instant1);
运行结果:

通过运行结果可以发现,时间戳和根据时区获取的时间戳输出时,仍然是格式化过的时间格式,且是由使用东八区的时间时,才与我电脑上的北京时间一致,同时输出的时间上有+08:00的输出;
另外,对于最后一个距离时间戳的时间,我们设置了60*23,即设置了23分钟,最后输出时间为:1970-01-01T00:23:00Z
5、计算时间差
(1)Duration:获取两个时间的时间差
(2)Period:获取两个日期的间隔
//计算时间差
//Duration:获取两个时间的时间差
//Period:获取两个日期的间隔 Instant instant2 = Instant.now();
Thread.sleep();
Instant instant3 = Instant.now();
Duration duration = Duration.between(instant2,instant3); log.info("duration.getSeconds()============={}", duration.getSeconds());
log.info("duration.toMillis()============={}", duration.toMillis());
log.info("duration.toHours()============={}", duration.toHours()); LocalDate localDate = LocalDate.of(,,);
LocalDate localDate1 = LocalDate.now();
log.info("LocalDate.now()============={}", localDate1);
Period period = Period.between(localDate,localDate1);
log.info("period============={}", period);
log.info("period.getYears()============={}", period.getYears());
log.info("period.getMonths()============={}", period.getMonths());
log.info("period.getDays()============={}", period.getDays());
运行结果:

(1)我们在代码中,让程序休眠了1秒,因此两个时间相差的秒数为1,毫秒数为1001是因为程序运行使用了1毫秒
(2)计算日期差时,我们使用了指定日期2018.10.6和当前日期(2020.6.2)做比较,输出为P1Y7M27D,表示差了1年7个月27天,然后使用get*获取时,获取的即这个输出的年、月、天
6、时间矫正器
(1)可以获取指定该年中的天数
(2)获取下一个指定的日期(下一个周日,JDK已提供)
(3)获取下一个工作日/结婚纪念日等(JDK未提供)
/**
* 时间矫正器
*/
@Test
public void test4(){
//TemporalAdjuster:时间矫正器
LocalDate localDate2 = LocalDate.now();
log.info("LocalDate.now()============={}", localDate2);
//指定时间
LocalDate localDate3 = localDate2.withDayOfYear();
log.info("withDayOfYear============={}", localDate3);
//获取下一个周日
LocalDate localDate4 = localDate2.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
log.info("TemporalAdjuster============={}", localDate4);
//自定义 下一个工作日
LocalDate localDate5 = localDate2.with((x)->{
LocalDate localDate6 = (LocalDate) x;
DayOfWeek dayOfWeek = localDate6.getDayOfWeek();
switch (dayOfWeek){
case FRIDAY:
return localDate6.plusDays();
case TUESDAY:
return localDate6.plusDays();
default:
return localDate6.plusDays();
}
});
log.info("下一个工作日============={}", localDate5);
}
输出结果:
-- ::26.457 INFO --- [ main] com.example.jdk8demo.Jdk8demoTest2 : LocalDate.now()=============--
-- ::26.461 INFO --- [ main] com.example.jdk8demo.Jdk8demoTest2 : withDayOfYear=============--
-- ::26.463 INFO --- [ main] com.example.jdk8demo.Jdk8demoTest2 : TemporalAdjuster=============--
-- ::26.464 INFO --- [ main] com.example.jdk8demo.Jdk8demoTest2 : 下一个工作日=============--
7、时间格式化
/**
* 时间日期格式化
*
*/
@Test
public void test6(){
DateTimeFormatter df = DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime ld = LocalDateTime.now();
String date = ld.format(df);
log.info("format==================={}",date); //自定义
DateTimeFormatter df1 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
date = ld.format(df1);
log.info("format==================={}",date);
//解析回原格式,此处要注意一点, HH时mm分ss秒大小写一定注意,错了就会反解析失败
LocalDateTime localDateTime = ld.parse(date,df1);
log.info("parse==================={}",localDateTime);
}
8、时区操作
(1)获取所有时区
(2)根据时区获取时间
(3)计算时区的时间差
/**
* 时区操作
* ZoneDate ZoneTime ZoneDateTime
*/
@Test
public void test7(){
//获取所有时区
Set<String> set = ZoneId.getAvailableZoneIds();
log.info("ZoneId.getAvailableZoneIds()================={}",JSON.toJSONString(set));
//根据时区获取时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Pacific/Fiji"));
LocalDateTime localDateTime1 = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
log.info("根据时区获取日期=========Pacific/Fiji==={}==========Asia/Shanghai==={}",localDateTime, localDateTime1);
//获取时差
ZonedDateTime zonedDateTime = localDateTime1.atZone(ZoneId.of("Pacific/Fiji"));
log.info("Shanghai与Fiji的时差========{}",zonedDateTime);
}
JDK8--09:全新的时间API的更多相关文章
- JDK8 新增的日期时间API
背景 JDK8中增加了一套全新的日期时间API,这里进行总结下,方便查询使用. 新的时间及日期API位于 java.time 包中,下面是一些关键类. Instant:代表的是时间戳. LocalDa ...
- JDK8中的新时间API:Duration Period和ChronoUnit介绍
目录 简介 Duration Period ChronoUnit 简介 在JDK8中,引入了三个非常有用的时间相关的API:Duration,Period和ChronoUnit. 他们都是用来对时间进 ...
- JDK8中新日期时间API
它们面临的问题是:可变性:像日期和时间这样的类应该是不可变的.偏移性:Date中的年份是从1900开始的,而月份都从0开始.格式化:格式化只对Date有用,Calendar则不行.此外,它们也不是线程 ...
- java 数据结构(三):java常用类 三 日期时间API
JDK 8之前日期时间API 1.获取系统当前时间:System类中的currentTimeMillis()long time = System.currentTimeMillis();//返回当前时 ...
- Java 常用类-程序员头大的日期时间API
第二节.日期时间API 一.JDK8之前日期时间API 1.1 java.lang.System类 System类提供的public static long currentTimeMillis()用来 ...
- Day029 JDK8中新日期和时间API (二)
# JDK8中新日期和时间API (二) Instant介绍 Instant:时间线上的一个瞬时点. 这可能被用来记录应用程序中的事件时间 戳. 在处理时间和日期的时候,我们通常会想到年,月,日,时, ...
- Day029 JDK8中新日期和时间API (四)
JDK8中新日期和时间API 其他的一些API ZoneId:该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris ZonedDateTime:一个在ISO-8601日历系统时区的 ...
- JDK8中的时间API
在Java 1.0中,对日期和时间的支持只能依赖java.util.Date类.正如类名所表达的,这个类无法表示日期,只能以毫秒的精度表示时间.更糟糕的是它的易用性,由于某些原因未知的设计决策,这个类 ...
- Java8 时间 API
前言 Java8 中最为人津津乐道的新改变恐怕当属函数式 API 的加入.但实际上,Java8 所加入的新功能远不止这个. 本文将基于<Java SE8 for the Really Impat ...
随机推荐
- POJ 2671 Jimmy's Bad Day题解(很详细很友好,类似区间dp)
有问题的话欢迎在评论区提出 题意: 题目链接 你是一个送快递的,现在给你一个环,环的边有权值,代表走这条边所花的时间,每个点代表一个地点,点有点权,代表这个点上有多少货物需要你送.初始时间\(t=0\ ...
- Chisel3 - model - Builder
https://mp.weixin.qq.com/s/THqyhoLbbuXXAtdQXRQDdA 介绍构建硬件模型的Builder. 1. DynamicContext 动态上下文 ...
- call 和 apply 的区别?哪个性能更好?
1.call 和 apply 都是 function 类 原型上的方法:每一个函数作为 function 的实例都能调用这两个方法:这两个方法执行的目的都是用来改变函数中 this 指向的,让函数执行 ...
- Java实现 蓝桥杯 算法训练 画图(暴力)
试题 算法训练 画图 问题描述 在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从x1到x2,纵坐标范围从y1到y2之间的区域涂上颜色. 下图给出了一个画了两个矩 ...
- Java实现 LeetCode 589 N叉树的前序遍历(遍历树)
589. N叉树的前序遍历 给定一个 N 叉树,返回其节点值的前序遍历. 例如,给定一个 3叉树 : 返回其前序遍历: [1,3,5,6,2,4]. 说明: 递归法很简单,你可以使用迭代法完成此题吗? ...
- Java实现 蓝桥杯 算法训练 p1103
算法训练 P1103 时间限制:1.0s 内存限制:256.0MB 编程实现两个复数的运算.设有两个复数 和 ,则他们的运算公式为: 要求:(1)定义一个结构体类型来描述复数. (2)复数之间的加法. ...
- Java实现 蓝桥杯VIP 算法提高 计算器
算法提高 计算器 时间限制:1.0s 内存限制:256.0MB [问题描述] 王小二的计算器上面的LED显示屏坏掉了,于是他找到了在计算器维修与应用系学习的你来为他修计算器. 屏幕上可以显示0~9的数 ...
- java实现 蓝桥杯 算法训练 Password Suspects
问题描述 在年轻的时候,我们故事中的英雄--国王 Copa--他的私人数据并不是完全安全地隐蔽.对他来说是,这不可接受的.因此,他发明了一种密码,好记又难以破解.后来,他才知道这种密码是一个长度为奇数 ...
- 使用macaca抓页面元素,执行命令后报安装失败处理Error: Command failed: ……pm install -r "/data/local/tmp/com.macaca.android.testing"
最近换了小米手机做自动化测试,执行命令的时候报安装失败错误,错误如下 解决:设置小米允许USB安装就好了 pm install -r "/data/local/tmp/com.macaca. ...
- Spring Cloud 系列之 Apollo 配置中心(四)
本篇文章为系列文章,未读前几集的同学请猛戳这里: Spring Cloud 系列之 Apollo 配置中心(一) Spring Cloud 系列之 Apollo 配置中心(二) Spring Clou ...