背景
1、JAVA面世之初,标准库引用了两种处理日期和时间的类。java.util.Date 和java.util.Calendar类。这两种类具有线程不安全风险。JAVASE8中引入java.time包解决了长久依赖的弊端,java.time包基于Joda-Time库组件。
2、目前项目中关于时间的运用场景
目标
1、掌握JAVA8中提供的java.time包中的常用日期类与相关方法
2、从Java.util包下的日期类过渡到java.time包下的日期类
3、掌握JAVA8中的日期与字符串之间的相互转换
老版本API计算问题
程序员小李出生于1995年12月16日,计算当前它已经出生了多少天?
步骤思路:
1、初始化Date对象无参构造(无参构造默认代表的是当前时间)
2、获取当前时间距离1970年1月1日过了多少毫秒
3、初始化Calendar对象并设时间为1995年12月16日,并将Calendar转换为Date对象,再转换为1995年12月16日距离1970年1月1日过了多少毫秒
4、将两个毫秒相减,然后将毫秒转换为天数结果
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args){
Date d = new Date();
long s1 = d.getTime();
Calendar c = Calendar.getInstance();
c.set(1995,11,16);
Date d2=c.getTime();
long s2 = d2.getTime();
Long intevarDay=(s1-s2)/1000/60/60/24;
System.out.println("1995年距离今天过了"+intevarDay+"天");
Long day = ChronoUnit.DAYS.between(LocalDate.of(1995,12,16),LocalDate.now());
System.out.println("1995年距离今天过了"+day+"天");
}
}
线程安全问题
1、SimpleDateFormat 类是线程不安全的,在多线程的情况下,全局共享一个
2、SimpleDateFormat 类中的Calendar对象有可能会出现异常
?问题:创建10个线程,将字符串“2018-12-12 12:12:12"转换为Date对象打印到控制台上
final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[ ] args){
for (int i =0;i<10;i++){
new Thread(
new Runnable() {
@Override
public void run (){
try{
Date date = SIMPLE_DATE_FORMAT.parse("2018-12-12 12:12:12");
System.out.println(date);
} catch(ParseException e) {
e.printStackTrace();
}
}
}
).start();
}
}
ALT+7 快捷键:
dea中查看类中所有方法列表当我们在开发中,或者在读别人代码时,如何能快速定位到想看的方法;我们以activiti中的RepositoryService为例,如下图,RepositoryService接口中定义了许多构造方法或普通方法。直接使用Alt+7快捷键盘,就可以看到左侧的RepositoryService查看当前文件中的所有方法
由于全局使用的是同一个Calendar对象 ,如果没有线程同步措施的话,那么可能会造成线程安全问题
final static SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[ ] args){
for (int i =0;i<10;i++){
new Thread(
new Runnable() {
@Override
public void run (){
try{
synchronized(SIMPLE_DATE_FORMAT ){
Date date = SIMPLE_DATE_FORMAT.parse("2018-12-12 12:12:12");
System.out.println(date);
}
} catch(ParseException e) {
e.printStackTrace();
}
}
}
).start();
}
}
线程安全问题:SimpleDateFormat 类是线程不安全的,在多线程的情况下,全局共享一个
SimpleDateFormat类中的Calendar 对象有可能会出现异常
另外一个问题:就是在java.util.Date和java.util.Calendar类之前,枚举类型(ENUM)还没有出现,所以在字段中使用整数常量导致整数常量都是可变的,而不是线程安全的。 为了处理 实际开发中遇到的问题,标准库随后引入了java.sql.Date作为java.util.Date的子类,但是还是没能彻底解决问题。最终JavaSE 8中引入了java.time包,这种全新的包从根本上解决了长久以来存在的诸多弊端,java.time包基于Joda-Time库构建,是一种免费的开源解决方案,实际上在Java 8没有出现之前,公司中已经广泛使用Joda-Time来解决Java中的日期与时间问题,Joda-Time的设计团队也参与了java.time包的开发。
public class CalendarUnsafeDemo{
//初始化Calendar对象封装日期为2008年8月8日
public static void main(String[ ] args){
//初始化Calendar对象 --》getInstance()方法
Calendar calendar = Calendar.getInstance();
// 通过set方法设置年/月/日参数 -》开发规范:不允许使用没有定义的魔法数字
// Calendar.set(2008,8,8)
Calendar.set(2008,Calendar.AUGUST,8)
}
}
java.time包->常用类的概述和功能介绍
Instant类
Instant类对时间轴上的单一瞬时点建模,可以用于记录应用程序中的事件时间戳,之后学习的类型转换中,均可以使用Instant类作为中间类完成转换。
Duration类
Duration类表示秒或纳秒时间间隔,适合处理较短的时间,需要更高的精确性。
Period类
Period类表示一段时间的年、月、日。
LocalDate类
LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日。
LocalTime类
LocalTime是一个不可变的日期时间对象,代表一个时间,通常被看作是小时-秒,时间表示为纳秒精度。
LocalDateTime类
LocalDateTime类是一个不可变的日期时间对象,代表日期时间,通常被视为年-月-日=时-分-秒。
ZonedDateTime类
ZonedDateTime是具有时区的日期时间的不可变表示,此类存储所有日期和时间字段,精度为纳秒,时区为区域偏移量,用于处理模糊的本地日期时间。
now方法在日期/时间类的使用
Date-Time API中的所有类均生成不可变实例,它们是线程安全的,并且这些类不提供公共构造函数,也就是说没办法通过new的方式直接创建,需要采用工厂方法加以实例化。
now方法在日期时间类中的应用
now方法在日期时间类中的应用2
不仅仅是以上提供的及各类可以使用now方法,Java8的Time包种还提供了其它几个类可以更精准的获取某些信息。
Year类(表示年)
YearMonth类(表示年月)
MonthDay类(表示月日)
of方法在日期/时间类的应用
指定任意时间节点
of方法可以根据给定的参数生成对应的日期/时间对象,基本上每个基本类都有of方法用于生成的对应的对象,而且重载形式对边,可以根据不同的参数生成对应的数据。
时区信息的获取(拓展)
在学习ZonedDateTime的时候,发现这个对象里面封装的不仅有时间日期,并且还有偏移量+时区,那么时区如何在Java中获取呢?通过提供的一个类ZonedId的getAvailableZoneIds方法可以获取到一个Set集合,集合中封装了600个时区。
添加时区信息与获取其它时区时间
我们可以通过给 LocalDateTimem添加时区信息来查看到不同时区的时间,比如说 LocalDateTime中当前封装的是上海时间,那么想知道此时此刻,纽约的时间是多少,就可以将纽约的时区Id添加进去,就可以查看到了,方式如下:
* 封装时间 LocalDateTime 并添加时区信息。
* 更改时区信息查看对应时间。
Month枚举类的使用
java.time包中引用了Month的枚举类,Month中包含标准日历中的12个月份的常量(从JANUARY到DECEMEBER)也提供了一些方便的方法供我们使用。
推荐在初始化LocalDate和LocalDateTime对象的时候,月份的参数使用枚举的方式传入,这样更简单易懂而且不易出错,因为如果是老的思维,Calendar传入0的话,那么会出现异常。
章节练习
1、创建当前时间(不带时区)
2、创建当前时间(只包含年月日)
3、创建当前时间(包含年月日时分秒且带有时区)
4、创建2012年12月31日7时38分46秒的日期对象,月份用枚举表示
5、创建2012年12月31日的时期对象,月份用枚举表示
6、创建7时38分46秒的时间对象