这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」
❤️作者简介:Java领域优质创作者🏆,CSDN博客专家认证🏆,华为云享专家认证🏆
❤️技术活,该赏
❤️点赞 👍 收藏 ⭐再看,养成习惯
大家好,我是小虚竹。之前有粉丝私聊我,问能不能把JAVA8 新的日期时间API(JSR-310)知识点梳理出来。答案是肯定的,谁让我宠粉呢。由于内容偏多,会拆成多篇来写。
闲话就聊到这,请看下面的正文。
常用于计算的类介绍
介绍下java8 中提供了几个常用于计算的类:
- Duration:表示秒和纳秒的时间量
- Period:表示年月日的时间量
- TemporalUnit:日期时间的基本单位
- TemporalField:日期时间的属性
- ValueRange:表示取值范围
Duration
Duration类说明
包路径:java.time.Duration
1 | java复制代码public final class Duration |
Duration 是TemporalAmount 的实现类,类里包含两个变量seconds 和 nanos ,所以Duration 是由秒和纳秒组成的时间量。
一个Duration实例是不可变的,当创建出对象后就不能改变它的值了。
Duration常用的用法
创建Duration对象
Duration 适合处理较短的时间,需要更高的精确性。我们能使用between()方法比较两个瞬间的差:
1 | java复制代码 Instant first = Instant.now(); |
可以通过LocalDateTime 类获取获取Duration对象
1 | java复制代码 LocalDateTime first = LocalDateTime.of(2021, 8, 30, 23, 14, 20); |
访问Duration的时间
Duration 对象中可以获取秒和纳秒属性。但没有毫秒属性,跟System.getCurrentTimeMillis()不同。
1 | java复制代码 Instant first = Instant.now(); |
可以转换整个时间成其他单位,如纳秒,毫秒,分钟,小时,天
1 | java复制代码 Instant first = Instant.now(); |
由图上可知,getNano 方法和toNanos 方法不太一样,前者是获取这段时间的小于1s的部分,后者是整个时间转化为纳秒。
Duration计算
1 | java复制代码plusNanos() |
以plusSeconds 和minusSeconds 为例:
1 | java复制代码LocalDateTime first = LocalDateTime.of(2021, 8, 30, 23, 14, 20); |
由上面的验证可知,这些计算方法执行后,会返回一个新的Duration对象,原先的Duration对象不变。
Period
Period类说明
包路径:java.time.Period
1 | java复制代码public final class Period |
Period 是ChronoPeriod 的实现类,类里包含两个变量years ,months 和 days ,所以Period 是由年,月和日组成的时间量。
Period常用的用法
创建Period对象
1 | java复制代码 LocalDate first = LocalDate.of(2021, 8, 29); |
访问Period的时间
1 | java复制代码 LocalDate first = LocalDate.of(2021, 8, 28); |
可以转换整个时间成其他单位,月
1 | java复制代码LocalDate first = LocalDate.of(2021, 8, 29); LocalDate second = LocalDate.of(2022, 9, 30); Period period = Period.between(first, second); System.out.println(period); System.out.println("月:"+period.toTotalMonths()); |
由图上可知,getMonths 方法和toTotalMonths 方法不太一样,前者是获取这段时间的月的部分,后者是整个时间转化为以月为单位长度。
toTotalMonths 源码:
1 | java复制代码public long toTotalMonths() { return years * 12L + months; // no overflow } |
Duration计算
1 | java复制代码plusDays() |
以plusMonths 和minusMonths 为例:
1 | java复制代码 LocalDate first = LocalDate.of(2021, 8, 28); |
由上面的验证可知,这些计算方法执行后,会返回一个新的Period对象,原先的Period对象不变。
TemporalUnit
TemporalUnit类说明
包路径:java.time.temporal.TemporalUnit
1 | java复制代码public interface TemporalUnit {...}public enum ChronoUnit implements TemporalUnit { private final String name; private final Duration duration; ...} |
TemporalUnit 主要实现类是枚举类型ChronoUnit
一个ChronoUnit成员会维护一个字符串名字属性name和一个Duration类型的实例。
其中ChronoUnit枚举了标准的日期时间单位集合,就是常用的年、月、日、小时、分钟、秒、毫秒、微秒、纳秒,这些时间单位的时间量到底是多少,代表多长的时间,在该枚举类中都有定义。
1 | java复制代码public enum ChronoUnit implements TemporalUnit { |
ChronoUnit常用的用法
1 | java复制代码 LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 30, 23, 14, 20); |
TemporalField
TemporalField类说明
包路径:java.time.temporal.TemporalField
1 | java复制代码public interface TemporalField { |
TemporalField 主要实现类是枚举类型ChronoField
一个ChronoField成员会维护一个字符串名字属性name、一个TemporalUnit的基础单位baseUnit、一个TemporalUnit的表示范围的单位rangeUnit和一个ValueRange类型的range用于表示当前属性的范围。
1 | java复制代码public enum ChronoField implements TemporalField { |
ChronoField常用的用法
ALIGNED_WEEK_OF_MONTH 和 ALIGNED_DAY_OF_WEEK_IN_MONTH 使用示例
1 | java复制代码 //每七天一周,2021-08-31 是周二,对应的值是3 |
ValueRange
ValueRange类说明
ValueRange 表示取值范围。
1 | java复制代码public final class ValueRange implements Serializable { |
ValueRange常用的用法
1 | ini复制代码ValueRange valueRange = ValueRange.of(1L, 10000L); |
1 | java复制代码 LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 30, 23, 14, 20); |
Chronology 判断是否闰年
判断是否闰年是由年表Chronology 提供的,通常情况下,我们使用ISO下的年表,是IsoChronology 。
看下代码实现
1 | java复制代码 @Override |
好精炼的代码,值得我们研究研究
闰年的基本判定方法:
1、非整百年:能被4整除的为闰年。(如2004年就是闰年,2001年不是闰年)
2、整百年:能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
1 | java复制代码((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0); |
这段代码用了两个条件,这两个条件都符合,才是闰年。
- (prolepticYear & 3) == 0
- (prolepticYear % 100) != 0 || (prolepticYear % 400) == 0
(prolepticYear & 3) == 0 用了与运算符“&”,其使用规律如下:
两个操作数中位都为1,结果才为1,否则结果为0。
3 的二进制是011 ,prolepticYear & 3 目的是保留最后2位二进制数,然后判断是否最后两位二进制数等于0。如果等于0,证明能被4整除。闰年一定要满足是4的倍数的条件;
(prolepticYear % 100) != 0 || (prolepticYear % 400) == 0 这个就比较好理解了,看是不是100的倍数或者是不是400 倍数。
而且小虚竹发现java.time.Year#isLeap() 用的实现代码逻辑是一样的
1 | java复制代码public static boolean isLeap(long year) { |
即使是巨佬写的代码,也存在代码的复用性问题
上面IsoChronology 是对Chronology接口接口的isLeapYear实现,MinguoChronology等实现类的isLeapYear,互用了IsoChronology的isLeapYear方法。
1 | java复制代码//MinguoChronology |
巨佬是有考虑复用的,在MinguoChronology等实现类已经有复用了。
java.time.Year#isLeap() 的优先级高,因为它是静态方法。isoChronology ** 可以引Year.isLeap**
Year ** 不可以引Chronology.isLeapYear** 。
博主发现在IsoChronology ** 的resolveYMD** 中已经存在了对Year.isLeap 的引用。
有的工具类会为了减少外部类依赖,重新写一次底层方法,避免外部类(或是不在一个包底下)的类依赖,这个已经用了,说不过去 。所以代码是存在复用性问题的。
实战
1 | java复制代码 int year = 2020; |
比较日期时间的先后
基本上都有这四个比较方法::compareTo()、isBefore()、isAfter()、和equals()
比较-LocalDate
1 | css复制代码 LocalDate localDate1 = LocalDate.of(2021, 8, 14); |
比较-LocalTime
1 | java复制代码 LocalTime localTime1 = LocalTime.of(23, 26, 30); |
比较-OffsetDateTime
1 | java复制代码 LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20); |
比较-OffsetTime
1 | java复制代码 LocalTime localTime1 = LocalTime.of( 13, 14, 20); |
比较-ZonedDateTime
1 | java复制代码 LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20); |
计算日期时间的间隔
Duration 和**Period ** 都有 **between ** 方法
这个就不在重复说了,上面Duration 和Period 的常用用法里有介绍到。
TemporalAdjuster 日期校准器
序号 | 方法 | 描述 |
---|---|---|
1 | dayOfWeekInMonth | 返回同一个月中每周的第几天 |
2 | firstDayOfMonth | 返回当月的第一天 |
3 | firstDayOfNextMonth | 返回下月的第一天 |
4 | firstDayOfNextYear | 返回下一年的第一天 |
5 | firstDayOfYear | 返回本年的第一天 |
6 | firstInMonth | 返回同一个月中第一个星期几 |
7 | lastDayOfMonth | 返回当月的最后一天 |
8 | lastDayOfNextMonth | 返回下月的最后一天 |
9 | lastDayOfNextYear | 返回下一年的最后一天 |
0 | lastDayOfYear | 返回本年的最后一天 |
11 | lastInMonth | 返回同一个月中最后一个星期几 |
12 | next / previous | 返回后一个/前一个给定的星期几 |
13 | nextOrSame / previousOrSame | 返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回 |
1 | less复制代码LocalDateTime now = LocalDateTime.of(2021,9,8,0,20,13); |
推荐相关文章
hutool日期时间系列文章
2DateUtil(时间工具类)-常用的时间类型Date,DateTime,Calendar和TemporalAccessor(LocalDateTime)转换
9LocalDateTimeUtil(JDK8+中的{@link LocalDateTime} 工具类封装)
10TemporalAccessorUtil{@link TemporalAccessor} 工具类封装
其他
java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案
高级JAVA开发必备技能:时区的规则发生变化时,如何同步JDK的时区规则
本文转载自: 掘金