java⽇期减⼀天_Java8⽇期时间API
在Java8之前,对于⽇期和时间的处理是能过Date和Calendar来完成的,因为长时间没接触Java了,我对⽇期的处理也还停留在它
们上,最近重新学Java才知道,Java8新推出了⼀套⽇期处理的API,在这就来探讨⼀下它们跟之前的⽇期处理类有什么不同,和新的
API有什么优点,怎么使⽤。
本⽂将以下顺序去展开:
1.为什么要推出新的⽇期处理API,过去的⽇期处理存在哪些问题?
8的⽇期API做了哪些优化,有什么新功能?
8的⽇期API的使⽤。
Date存在的问题
先来看看Date存在⼀些什么问题,我在⽹上查了⼀些资料,都是说Date存在线程安全和易⽤性上的问题。先来看看具体是怎样的问题。
线程安全问题
写段程序在多线程下跑⼀下⽇期格式化
publicstaticvoidmain(String[]args){
SimpleDateFormatsimpleDateFormat=newSimpleDateFormat("yyyy-MM-dd");
for(inti=0;i5;i++){
newThread(()->{
for(;;){
try{
n(tThread()+":"+(newDate((newRandom().nextLong()))));
}catch(Exceptione){
tackTrace();
(1);
}
}
}).start();
}
}
可以看到,程序运⾏中途报错了
我们点进SimpleDateFormat的源码看看,SimpleDateFormat继承于DateFormat,⽽DateFormat内部保存着⼀个全局的calendar对象的,⽽
对⽇期的格式化或者解析都是要操作这个对象。然后我们再来看看format这个⽅法的源码。
可以看到在第943⾏,对calendar赋值了需要格式化的date对象,如果在多线程环境下,线程1设置了calendar的时间,但是还没完成格式
化的逻辑,这⾥线程2⼜对calendar设置时间的时候,覆盖了线程1的设置,那么线程1在后⾯读取calendar对象的时间就会导致报错。为了
解决这个问题,只能给每个线程都创建⼀个SimpleDateFormat,跟其它线程隔离起来。
同理,对于par⽅法,每⼀次把⽇期字符串解析成对象时,calendar都会把上⼀次的保存的⽇期时间信息全部清空,然后保存最新的⽇期
时间信息,在多线程下就会出来,线程1设置了⽇期时间后,线程2⼜把它给清空了,最后程序就会报错了。
par⽅法最后会调⽤下⾯的⽅法,在第114⾏对⽇期信息进⾏了清空。
易⽤性
相信Date和Calendar的难⽤⼤家都清楚。就随便举例⼏点。
Date的⽉份开始是从0开始,以11结束的,每次操作⽉份都要做加1操作跟现在⽉份匹配上。
想要对⽇期进⾏运算,加⼀天,减⼀天,加⼀个⽉,减⼀个⽉等操作,只能通过Calendar来进⾏,Date和Calendar转换来转换去相当的⿇
烦。
Date把⽇期、时间揉合在了⼀起,当⾯临只需要处理⽇期部分或者时间部分的场景,Date就显得有点臃肿了,⽽且Date的输出可读性也不
好,不对它进⾏格式化的话看起来很难受。
Java8新⽇期API
基于上述问题,在Java8对⽇期进⾏了优化,⾸先是将⽇期和时间设计为不可变类型,就像String类型⼀样,这样就避免了多线程下对⽇
期的修改导致的线程安全问题,每次对⽇期的操作都会⽣成⼀个新的⽇期对象;另外还把功能进⼀步细化了,对⽇期的运算更加便利,输出
也更加⼈性化。
下⾯来看看Java8主要提供了哪⼀些常⽤的⽇期API。
从上图可以看到,Java8把⽇期和时间拆分出来了,LocalDateTime包含⽇期和时间,LocalDate只包含⽇期部分,LocalTime只包含时间
部分,Instant代表时间线上的⼀个瞬时时间点,但默认时区是UTC+0的。
publicstaticvoidmain(String[]args){
n("LocalDateTime:"+());
n("LocalDate:"+());
n("LocalTime:"+());
n("Instant:(UTC+0)"+());
n("Instant:(UTC+8)"+().atZone(Default()));
}
LocalDateTime、LocalDate、LocalTime、Instant都实现了Temporal和TemporalAdjuster接⼝,Temporal提供了⼀些对⽇期运算的接⼝,
如对⽇期的加减,TemporalAdjuster提供只提供了⼀个接⼝,⽤于对⽇期/时间对象的调整。
另外LocalDateTime内部只是封装了LocalDate和LocalTime,当对LocalDateTime进⾏操作时,都是针对指定的⽇期或者时间部分去进⾏操
作的。
另外LocalDateTime、LocalDate、LocalTime、Instant在运算中都有各⾃约束的范围,LocalDateTime可以⽀持⽇期和时间的运
算;LocalDate只⽀持最⼩粒度为1天的运算,不能LocalDate上对时间进⾏运算;LocalTime⽀持纳秒到⼩时的运算,不能对⽇期进⾏运
算;Instant只⽀持纳秒到秒的运算。如果进⾏超出规定范围内的运算就抛出不⽀持的异常。
但是LocalTime和Instant的plus有些特殊,⽀持到天的运算,是因为plus在内部把天转换为在范围内的单位再进⾏运算。
Java8新⽇期API的使⽤
上⾯讲到了Java8对⽇期API在安全性和易⽤性上的优化。现在来总结⼀下⽇常常⽤API具体怎么⽤。
这⾥以LocalDate为例,LocalDateTime和LocalTime的⽤法差不多。
publicstaticvoidmain(String[]args){
//获取当天⽇期时间
LocalDatetoday=();
print("获取当天⽇期时间:",today);
//加⼀天
LocalDatetomorrow=ys(1);
print("加⼀天:",tomorrow);
//加⼀个⽉
LocalDatenextMonth=nths(1);
print("加⼀个⽉:",nextMonth);
//减⼀天
LocalDateyesterday=ays(1);
print("减⼀天:",yesterday);
//减⼀个⽉
LocalDatelastMonth=onths(1);
print("减⼀个⽉:",lastMonth);
//获取今天是本⽉第⼏天
intdayOfMonth=OfMonth();
print("获取今天是本⽉第⼏天:",dayOfMonth);
//获取今天是本周第⼏天
intdayOfWeek=OfWeek().getValue();
print("获取今天是本周第⼏天:",dayOfWeek);
//获取今天是本年第⼏天
intdayOfYear=OfYear();
print("获取今天是本年第⼏天:",dayOfYear);
//获取本⽉天数。
intdaysOfMonth=OfMonth();
print("获取本⽉天数:",daysOfMonth);
//获取本年天数
intdaysOfYear=OfYear();
print("获取本年天数:",daysOfYear);
//获取本⽉指定的第n天
LocalDatedate1=yOfMonth(15);
print("获取本⽉指定的第n天:",date1);
//获取本⽉的最后⼀天
LocalDatelastDaysOfMonth=(yOfMonth());
print("获取本⽉的最后⼀天:",lastDaysOfMonth);
//⽇期字符串解析。严格按照ISOyyyy-MM-dd验证
LocalDatedate=("2021-01-17");
print("⽇期字符串解析:",date);
//⽇期字符串解析。⾃定义格式
DateTimeFormatterdft=ern("yyyy-M-dd");
LocalDatedate2=("2021-1-17",dft);
print("⽇期字符串解析(⽇期字符串解析):",date2);
//格式化⽇期
StringdateStr=(dft);
print("格式化⽇期:",dateStr);
//⾃定义⽇期
LocalDatecusDate=(2020,8,14);
print("⾃定义⽇期:",cusDate);
//⽇期⽐较
booleanbefore=re(tomorrow);
print("今天是否⽐明天早:",before);
booleanbefore1=re(yesterday);
print("今天是否⽐昨天早:",before1);
booleanafter=r(tomorrow);
print("今天是否⽐明天晚:",after);
booleanafter1=r(yesterday);
print("今天是否⽐昨天晚:",after1);
//获取两个时间相差多少天/周/⽉...根据单位不同返回不同
longuntil=(nextMonth,);
print("今天到下个⽉相差⼏周:",until);
Monthmonth=th();
print("⽉份:",month);
print("⽉份:",ue());
}
从最后⽉份的输出可以看出,Java8把⽉份优化成了⼀个枚举类,也把⽉份区间调整为1~12了。
Duration和Period
Java8还提供了2个计算两个时间/⽇期差的API。
Duration⾥⾯封装了conds和nanos,前者是秒,后者是纳秒,代表着两个时间间的差值;
⽽Period⾥⾯封装了day,month,years3个属性,代表的是两个⽇期间的差值。
所以,Duration只能计算包含有时间的对象,⽐如LocalDateTime,LocalTime,Instant,如果计算LocalDate的话会不⽀持的异常。
同理,Period也就只⽀持LocalDate的计算。
下⾯来看看它们有哪些⽤法。
Duration
publicstaticvoidmain(String[]args){
LocalDateTimetoday=();
LocalDateTimetomorrow=ys(1);
//根据两个时间获取Duration
Durationduration=n(today,tomorrow);
print("获取纳秒数差值:",s());
print("获取毫秒数差值:",is());
print("获取秒数差值:",onds());
print("获取分钟数差值:",tes());
print("获取⼩时数差值:",s());
print("获取天数差值:",());
//当第1个时间⽐第2个时间⼩时为fal,反之true。可以⽤来判断2个时间的⼤⼩。
booleannegative=tive();
print("isNegative:",negative);
//以1天的差值创建Duration
Durationduration1=(1);
print("以1天的差值创建Duration:",onds());
}
Duration也⽀持plus和minus操作,这⾥就不演⽰了。
另外Duration还有个功能,可以通过解析字符串来⽣成对象。字符串的规则是这样:。P为固定开头,n为数字,D为天
数,T代表后⾯是时间部分,H、M、S分别时、分、秒。字母⼤⼩写不敏感,可⼤写可⼩写。另外还⽀持+和-。+为往上加时间,-为往下减
时间。
publicstaticvoidmain(String[]args){
Durationduration=("P1DT1H1M1S");
print("当前时间加上1天1⼩时1分钟1秒的差值:",onds());
Durationduration1=("P2D");
print("当前时间加上2天的差值:",onds());
Durationduration2=("PT2H");
print("当前时间加上2⼩时的差值:",onds());
Durationduration3=("PT-2H");
print("当前时间减去2⼩时的差值:",onds());
Durationduration4=("PT-2H30M");
print("当前时间减去1⼩30分的差值:",onds());
Durationduration5=("PT-2H-30M");
print("当前时间减去2⼩30分的差值:",onds());
//上⾯的也可以写成这样
Durationduration6=("-PT2H30M");
print("当前时间减去2⼩30分的差值:",onds());
}
每个n前⾯都是隐式的添加了⼀个+,像-2H30M这种意思就是减去2个⼩时再加30分钟,那就是1个⼩时30分钟咯;但是如果在P前⾯加⼀
个-的话,会对⾥⾯所有的数字都会产⽣影响。其实就是像⼩学数学⼀样,⽤括号把括起来,(),在最外⾯
加⼀个-,那⾥⾯的符号就全部取反了,但是单独在某个数字前加的话只会影响到它⾃⼰。
Period
Period跟Duration其实⽤法差不多,都是表达时间上的差值。只不过⼀个是表达⽇期,⼀个是表达时间,粒度不同。就不演⽰了。
总结
Java8的⽇期处理API常⽤的功能⽅法总结得差不多了,基本上⽇常使⽤的也就⼤概这么多了,这⼀套⽇期API搞清楚它们的区别和背后
逻辑后⽤起来很⽅便,本⽂没有讲到的⽤法,开发使⽤的时候查⼀下⽂档也可以马上⽤起来了,底层都是这些基础的知识点。
本文发布于:2022-12-28 13:05:05,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/46800.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |