高级JAVA开发必须掌握技能java8 新日期时间API(JSR-310:常用的日期时间API),4万字详解(全程干货,建议收藏)
Posted 小虚竹
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了高级JAVA开发必须掌握技能java8 新日期时间API(JSR-310:常用的日期时间API),4万字详解(全程干货,建议收藏)相关的知识,希望对你有一定的参考价值。
技术活,该赏
点赞,收藏再看,养成习惯
大家好,我是小虚竹。之前有粉丝私聊我,问能不能把JAVA8 新的日期时间API(JSR-310)知识点梳理出来。答案是肯定的,谁让我宠粉呢。由于内容偏多(超十万字了),会拆成多篇来写。
闲话就聊到这,请看下面的正文。
文章目录
常用的日期时间API简介
介绍下java8API比较常用的日期时间API,按java.time 包的类顺序:
- Clock:时钟
- Instant:瞬间时间。
- LocalDate:本地日期。只有表示年月日
- LocalDateTime:本地日期时间,LocalDate+LocalTime
- LocalTime:本地时间,只有表示时分秒
- OffsetDateTime:有时间偏移量的日期时间(不包含基于ZoneRegion的时间偏移量)
- OffsetTime:有时间偏移量的时间
- ZonedDateTime:有时间偏移量的日期时间(包含基于ZoneRegion的时间偏移量)
博主把这些类都点开看了,都是属于不可变类。而且官方也说了,java.time包 下的类都是线程安全的。
Clock
Clock类说明
public abstract class Clock {
...
}
Clock 是抽象类,内部提供了四个内部类,这是它的内部实现类
- FixedClock :始终返回相同瞬间的时钟,通常使用于测试。
- OffsetClock :偏移时钟,时间偏移量的单位是Duration。
- SystemClock :系统默认本地时钟。
- TickClock :偏移时钟,时间偏移量的单位是纳秒。
Clock 提供了下面这几个常用的方法(这几个方法在实现类里都有对应的实现):
// 获取时钟的当前Instant对象。
public abstract Instant instant()
// 获取时钟的当前毫秒数值
public long millis()
// 获取用于创建时钟的时区。
public abstract ZoneId getZone()
// 返回具有指定时区的当前时钟的新实例
public abstract Clock withZone(ZoneId zone)
FixedClock
Clock.fixed
public static Clock fixed(Instant fixedInstant, ZoneId zone)
需要传递instant
和zone
,并将返回具有固定瞬间的时钟。
Instant instant = Instant.now();
Clock fixedClock = Clock.fixed(instant, ZoneId.of("Asia/Shanghai"));
Clock fixedClock1 = Clock.fixed(instant, ZoneId.of("GMT"));
System.out.println("中国时区的Clock:"+fixedClock);
System.out.println("GMT时区的Clock:"+fixedClock1);
由运行结果可知,返回的结果是有带对应时区的。
验证获取的时钟会不会改变:
Clock clock = Clock.systemDefaultZone();
Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
System.out.println(fixedClock.instant());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(fixedClock.instant());
Clock.fixed 创建一个固定的时钟,clock 对象将始终提供与指定相同的时刻。。如图所示,强制睡眠1秒,但是时刻没变。
Clock.fixed 跟 Offset 方法更配
由上面可知Clock.fixed 得到一个固定的时钟,那要添加时间或者减去时间就要用到Offset 方法
示例代码如下
Clock clock = Clock.systemDefaultZone();
Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
System.out.println(fixedClock.instant());
Clock clockAdd = Clock.offset(clock, Duration.ofMinutes(20));
Clock clockSub = Clock.offset(clock, Duration.ofMinutes(-10));
System.out.println("原先的: " + clock.instant());
System.out.println("加了20分钟: " + clockAdd.instant());
System.out.println("减了10分钟: " + clockSub.instant());
OffsetClock
OffsetClock 是偏移时钟,时间偏移量的单位是Duration。
//Clock
public static Clock offset(Clock baseClock, Duration offsetDuration) {
Objects.requireNonNull(baseClock, "baseClock");
Objects.requireNonNull(offsetDuration, "offsetDuration");
if (offsetDuration.equals(Duration.ZERO)) {
return baseClock;
}
return new OffsetClock(baseClock, offsetDuration);
}
由源码可知,使用Clock.offset方法 返回的是OffsetClock实例对象
Clock clock = Clock.systemDefaultZone();
Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
System.out.println(fixedClock.instant());
Clock clockAdd = Clock.offset(clock, Duration.ofMinutes(20));
System.out.println("原先的: " + clock.instant());
System.out.println("加了20分钟: " + clockAdd.instant());
SystemClock
SystemClock 是系统默认的本地时钟。
Clock clock = Clock.systemDefaultZone(); System.out.println(clock.millis()); Clock utc = Clock.systemUTC(); System.out.println(utc.millis()); System.out.println(System.currentTimeMillis());
居然完全一样。这就要看下源码了
Clock.systemDefaultZone()
用的是系统默认的时区ZoneId.systemDefault()
public static Clock systemDefaultZone() {
return new SystemClock(ZoneId.systemDefault());
}
最终调用的也是System.currentTimeMillis()
Clock.systemUTC()
用的是UTC时区ZoneOffset.UTC
public static Clock systemUTC() { return new SystemClock(ZoneOffset.UTC); }
最终调用的也是System.currentTimeMillis()
结论
Clock.systemDefaultZone() 和Clock.systemUTC()获取的millis()时间戳是一样的,就是对应时区的差别。
TickClock
TickClock 是偏移时钟,时间偏移量的最小单位是纳秒。
如图所示,Clock主要提供下面三个方法
//构造的时钟的计时单位是自定义的偏移量单位public static Clock tick(Clock baseClock, Duration tickDuration); //构造的时钟的计时单位是分 public static Clock tickMinutes(ZoneId zone);//构造的时钟的计时单位是秒public static Clock tickSeconds(ZoneId zone) ;
实战:
Clock tickClock = Clock.tick(Clock.systemDefaultZone(),Duration.ofHours(1L)); Clock tickMinutes = Clock.tickMinutes(ZoneId.of("Asia/Shanghai")); Clock tickSeconds = Clock.tickSeconds(ZoneId.of("Asia/Shanghai")); LocalDateTime tickClockLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickClock.millis()),ZoneId.of("Asia/Shanghai")); LocalDateTime tickMinutesLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickMinutes.millis()),ZoneId.of("Asia/Shanghai")); LocalDateTime tickSecondsLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickSeconds.millis()),ZoneId.of("Asia/Shanghai")); System.out.println("tickClock :"+tickClock.millis() +" 转为date时间:"+tickClockLocalDateTime); System.out.println("tickMinutes:"+tickMinutes.millis() +" 转为date时间:"+tickMinutesLocalDateTime); System.out.println("tickSeconds:"+tickSeconds.millis() +" 转为date时间:"+tickSecondsLocalDateTime);
偏移量的单位支持:天,时,分,秒,豪秒,纳秒
Instant
Instant类说明
public final class Instant implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable { ... }
Instant表示瞬间时间。也是不可变类且是线程安全的。其实Java.time 这个包是线程安全的。
Instant是java 8新增的特性,里面有两个核心的字段
... private final long seconds; private final int nanos; ...
一个是单位为秒的时间戳,另一个是单位为纳秒的时间戳。
是不是跟**System.currentTimeMillis()**返回的long时间戳很像,System.currentTimeMillis()返回的是毫秒级,Instant多了更精确的纳秒级时间戳。
Instant常用的用法
Instant now = Instant.now();
System.out.println("now:"+now);
System.out.println(now.getEpochSecond()); // 秒
System.out.println(now.toEpochMilli()); // 毫秒
Instant是没有时区的,但是Instant加上时区后,可以转化为ZonedDateTime
Instant ins = Instant.now();
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
System.out.println(zdt);
long型时间戳转Instant
要注意long型时间戳的时间单位选择Instant对应的方法转化
//1626796436 为秒级时间戳Instant ins = Instant.ofEpochSecond(1626796436);ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());System.out.println("秒级时间戳转化:"+zdt);//1626796436111l 为秒级时间戳Instant ins1 = Instant.ofEpochMilli(1626796436111l);ZonedDateTime zdt1 = ins1.atZone(ZoneId.systemDefault());System.out.println("毫秒级时间戳转化:"+zdt1);
Instant的坑
Instant.now()获取的时间与北京时间相差8个时区,这是一个细节,要避坑。
看源码,用的是UTC时间。
public static Instant now() { return Clock.systemUTC().instant(); }
解决方案:
Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));System.out.println("now:"+now);
LocalDate
LocalDate类说明
LocalDate表示本地日期。只有表示年月日。相当于:yyyy-MM-dd。
LocalDate常用的用法
获取当前日期
LocalDate localDate1 = LocalDate.now(); LocalDate localDate2 = LocalDate.now(ZoneId.of("Asia/Shanghai")); LocalDate localDate3 = LocalDate.now(Clock.systemUTC()); System.out.println("now :"+localDate1); System.out.println("now by zone :"+localDate2); System.out.println("now by Clock:"+localDate3);
获取localDate对象
LocalDate localDate1 = LocalDate.of(2021, 8, 14); LocalDate localDate2 = LocalDate.parse("2021-08-14"); System.out.println(localDate1); System.out.println(localDate2);
获取指定日期的年月日
LocalDate localDate1 = LocalDate.of(2021, 8, 14); // 当前日期年份:2021 System.out.println(localDate1.getYear()); // 当前日期月份对象:AUGUST System.out.println(localDate1.getMonth()); // 当前日期月份:8 System.out.println(localDate1.getMonthValue()); // 该日期是当前周的第几天:6 System.out.println(localDate1.getDayOfWeek().getValue()); // 该日期是当前月的第几天:14 System.out.println(localDate1.getDayOfMonth()); // 该日期是当前年的第几天:226 System.out.println(localDate1.getDayOfYear());
修改年月日
LocalDate localDate1 = LocalDate.of(2021, 8, 14); // 修改该日期的年份:2022-08-14 System.out.println(localDate1.withYear(2022)); // 修改该日期的月份:2021-12-14 System.out.println(localDate1.withMonth(12)); // 修改该日期在当月的天数:2021-08-01 System.out.println(localDate1.withDayOfMonth(1));
比较日期
LocalDate localDate1 = LocalDate.of(2021, 8, 14); // 比较指定日期和参数日期,返回正数,那么指定日期时间较晚(数字较大):13 int i = localDate1.compareTo(LocalDate.of(2021, 8, 1)); System.out.println(i); // 比较指定日期是否比参数日期早(true为早):true System.out.println(localDate1.isBefore(LocalDate.of(2021,8,31))); // 比较指定日期是否比参数日期晚(true为晚):false System.out.println(localDate1.isAfter(LocalDate.of(2021,8,31))); // 比较两个日期是否相等:true System.out.println(localDate1.isEqual(LocalDate.of(2021, 8, 14)));
LocalDate 和String相互转化、Date和LocalDate相互转化
LocalDate 和String相互转化
LocalDate localDate1 = LocalDate.of(2021, 8, 14); // LocalDate 转 String DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String dateString = localDate1.format(dateTimeFormatter); System.out.println("LocalDate 转 String:"+dateString); // String 转 LocalDate String str = "2021-08-14"; DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd"); LocalDate date = LocalDate.parse(str, fmt); System.out.println("String 转 LocalDate:"+date);
Date和LocalDate相互转化
// Date 转 LocalDate
Date now = new Date();
// 先将Date转换为ZonedDateTime
Instant instant = now.toInstant();
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("Asia/Shanghai"));
LocalDate localDate = zonedDateTime.toLocalDate();
// Sat Aug 14 23:16:28 CST 2021
System.out.println(now);
// 2021-08-14
System.out.println(localDate);
// LocalDate 转 Date
LocalDate now1 = LocalDate.now();
ZonedDateTime dateTime = now1.atStartOfDay(ZoneId.of("Asia/Shanghai"));
Date date1 = Date.from(dateTime.toInstant());
System.out.println(date1);
LocalDateTime
LocalDateTime类说明
表示当前日期时间,相当于:yyyy-MM-ddTHH:mm:ss
LocalDateTime常用的用法
获取当前日期和时间
LocalDate d = LocalDate.now(); // 当前日期
LocalTime t = LocalTime.now(); // 当前时间
LocalDateTime dt = LocalDateTime.now(); // 当前日期和时间
System.out.println(d); // 严格按照ISO 8601格式打印
System.out.println(t); // 严格按照ISO 8601格式打印
System.out.println(dt); // 严格按照ISO 8601格式打印
由运行结果可行,本地日期时间通过now()获取到的总是以当前默认时区返回的
获取指定日期和时间
LocalDate d2 = LocalDate.of(2021, 07, 14); // 2021-07-14, 注意07=07月 LocalTime t2 = LocalTime.of(13, 14, 20); // 13:14:20 LocalDateTime dt2 = LocalDateTime.of(2021, 07, 14, 13, 14, 20); LocalDateTime dt3 = LocalDateTime.of(d2, t2); System.out.println("指定日期时间:"+dt2); System.out.println("指定日期时间:"+dt3);
日期时间的加减法及修改
LocalDateTim以上是关于高级JAVA开发必须掌握技能java8 新日期时间API(JSR-310:常用的日期时间API),4万字详解(全程干货,建议收藏)的主要内容,如果未能解决你的问题,请参考以下文章
高级JAVA开发必备技能:java8 新日期时间API(JSR-310:常用的日期时间API)(JAVA 小虚竹)
高级JAVA开发必备技能:java8 新日期时间API(JSR-310:实战+源码分析)(JAVA 小虚竹)
高级JAVA开发必备技能:java8 新日期时间API(JSR-310:常用计算工具)(JAVA 小虚竹)
高级JAVA开发必备技能:java8 新日期时间API(JSR-310:格式化和解析)(JAVA 小虚竹)
高级JAVA开发必备技能:java8 新日期时间API(JSR-310:ZoneId 时区和偏移量)(JAVA 小虚竹)
❤️高级JAVA开发必备技能❤️java8 新日期时间API(JSR-310:实战+源码分析),5万字详解(JAVA 小虚竹,建议收藏)