1.旧版本存在的问题
相信有开发经验的朋友都清楚Java旧版的时间方面的API设计不合理,没有时区支持、日期时间的计算和时间格式的转化都很麻烦。且时间格式转换在多线程环境下容易出现线程安全问题
因此,一般小姜在平时的开发中使用hutool的工具类进行时间的计算,在ThreadLocal中加入SimpleDateFormat供该线程共享
2.新版本的改进
JDK8中新增加了一套全新的七日时间API,这套API的设计合理,并且是线程安全的,主要的类有
- LOcalDate: 表示日期,例如 2000-01-01
- LocalTime: 表示时间,例如 12:00:00.200
- LocalDateTime: 标识日期时间,例如 2000-01-01 12:00:00.200
- DateTimeFormatter: 日期时间格式化类
- Instant: 时间戳,表示某一个瞬间
- Duration: 用于计算两个时间(LocalTime,时分秒)之间的差值
- Perlod: 用于计算两个日期(LOcalDate,年月日)之间的差值
- ZonedDateTime: 支持时区的日期时间
除此之外,默认情况下我们使用的是公元纪年也就是公历,JDK8还提供了其他历法:
- ThaiBuddhistDate 泰国佛教历
- MinguoDate 中华民国历
- JapaneseDate 日本历
- HijrahDate 伊斯兰历
了解这些之后,我们来看一下JDK8相关的时间操作
3.JDK8时间相关操作
3.1创建时间
// 旧版本创建日期
Date oldDate = new Date(2000, 1, 1);
System.out.println(oldDate);
// 新版本创建日期
LocalDate newDate = LocalDate.of(2000, 1, 1);
System.out.println(newDate);
执行结果:
可见,新版本创建的日期是完全正确的,而旧版本创建的却是3900年2月1日,这是因为旧版本的Date在传入参数的时候需要传递的年份参数是指定参数距离1900年的差值。比如2000年距离1900年差了100年那么Date就应该传入100,而月份传入参数的时候取0~11,0表示1月份;1标识2月份,以此类推11表示的就是12月份。
此外,严格来说Date创建的是2000-01-01 00:00:00这个时间点而不是单纯的表示2000-01-01这一天。新版本表示的更为准确,同时帮我们做了格式化。
3.2获取当前日期
// 获取当前日期
LocalDate now = LocalDate.now();
System.out.println("当前日期:" + now);
System.out.println("年: " + now.getYear());
System.out.println("月: " + now.getMonth().getValue());
System.out.println("日: " + now.getDayOfMonth());
System.out.println("星期: " + now.getDayOfWeek().getValue());
执行结果:
LocalDate对象获得的月份和星期几时枚举值,需要getValue()才能获取到响应的int值,以上结果,今天确实是2021年6月21日星期一
3.3时间操作
// 创建指定的时间
LocalTime time = LocalTime.of(12, 26, 30, 100);
System.out.println("指定时间:" + time);
LocalTime nowTime = LocalTime.now();
System.out.println("当前时间:" + nowTime);
System.out.println("时:" + nowTime.getHour());
System.out.println("分:" + nowTime.getMinute());
System.out.println("秒:" + nowTime.getSecond());
System.out.println("纳秒:" + nowTime.getNano());
执行结果
3.4日期时间操作
// 创建指定日期时间 2000-01-01 12:26:38
LocalDateTime dateTime = LocalDateTime.of(2000,1,1,12,26,38);
System.out.println("指定的日期时间:" + dateTime);
// 获取当前日期时间
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("当前的日期时间:" + nowDateTime);
System.out.println("年:" + nowDateTime.getYear());
System.out.println("月:" + nowDateTime.getMonth().getValue());
System.out.println("日:" + nowDateTime.getDayOfMonth());
System.out.println("时:" + nowDateTime.getHour());
System.out.println("分:" + nowDateTime.getMinute());
System.out.println("秒:" + nowDateTime.getSecond());
System.out.println("纳秒:" + nowDateTime.getNano());
System.out.println("星期:" + nowDateTime.getDayOfWeek().getValue());
3.5日期时间的修改
JDK8中修改日期时间的方法是dateTime.withXXX
看到名字就能知道是修改什么,比如说:
- withYear 修改年份
- withMonth 修改月份
- withDayOfMonth 修改在某月的第几天也就是几号
- …
// 创建指定日期时间 2000-01-01 12:26:38
LocalDateTime dateTime = LocalDateTime.of(2000,1,1,12,26,38);
System.out.println("指定的日期时间:" + dateTime);
// 修改年份为2008年
LocalDateTime dateTime20008 = dateTime.withYear(2008);
System.out.println(dateTime20008);
System.out.println(dateTime);
执行结果
以上结果可见,修改日期时间对象时;并不会修改原来的对象。而是会生成一个新的对象,复制原来的对象,然后修改制定的参数。如上面的代码中我将dateTime
对象中的年份改成2008年但是dateTime
对象中的年份并没有发生变化,而withYear
返回的对象dateTime20008
只是修改了制定的年份,其他并没法发生变化,因此若想一次修改多个参数可以这样做:
// 创建指定日期时间 2000-01-01 12:26:38
LocalDateTime dateTime = LocalDateTime.of(2000,1,1,12,26,38);
System.out.println("指定的日期时间:" + dateTime);
// 修改年份为2008-08-08 12:26:38
LocalDateTime dateTime20008 = dateTime.withYear(2008).withMonth(8).withDayOfMonth(8);
System.out.println(dateTime20008);
System.out.println(dateTime);
执行结果
可见,原来的dateTime也并没有变化dateTime.withXXX
方法返回的是一个新的对象
3.6时间的位移计算
在项目中有时我们需要计算当前时间n小时之前或n小时之后,此类的时间位移计算,在JDK8中提供了plusXXX
(加)和minusXXX
(减)方法用于进行位移计算。
plusXXX
用于进行日期时间的加法运算,常用的有:
- plusHours 计算n个小时之后的日期时间
- plusYears 计算n年之后的日期时间
- plusMonths 计算n个月之后的日期时间
- plusDays 计算n天之后的日期时间
- plusMinutes 计算n分钟之后的日期时间
- plusWeeks 计算n周之后的日期时间
minusXXX
用于进行日期时间的减法运算,常用的有:
- minusHours 计算n个小时之前的日期时间
- minusYears 计算n年之前的日期时间
- minusMonths 计算n个月之前的日期时间
- minusDays 计算n天之前的日期时间
- minusMinutes 计算n分钟之前的日期时间
- minusWeeks 计算n周之前的日期时间
// 获取当前日期时间
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("当前日期时间:" + nowDateTime);
// 进行时间的位移计算
System.out.println("一小时后:" + nowDateTime.plusHours(1));
System.out.println("2年后:" + nowDateTime.plusYears(2));
System.out.println("3个月后:" + nowDateTime.plusMonths(3));
System.out.println();
System.out.println("一天前:" + nowDateTime.minusDays(1));
System.out.println("10分钟前:" + nowDateTime.minusMinutes(10));
System.out.println("2周前:" + nowDateTime.minusWeeks(2));
执行结果
3.7 时间的比较
- date1.isAfter(date2) date1是否在date2之后
- date1.isBefore(date2) date1是否在date2之前
- date1.isLeapYear() date1所处年份是否是闰年
// 获取当前日期时间
LocalDate nowDate = LocalDate.now();
LocalDate date = LocalDate.of(2020, 2, 17);
System.out.println( "当前时间是否在 2020-02-17之后: " + nowDate.isAfter(date));
System.out.println("当前时间是否在 2020-02-17之前: " + nowDate.isBefore(date));
System.out.println("当前年份是否是闰年: " + nowDate.isLeapYear());
System.out.println("2020-02-17是否是闰年: " + date.isLeapYear());