Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

时间:2023-11-22 23:32:32

目录

0.前言

1.TemporalAccessor源码

2.Temporal源码

3.TemporalAdjuster源码

4.ChronoLocalDate源码

5.LocalDate源码

6.总结

0.前言

  通过前面Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中主要的类关系简图如下:

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

可以看出主要的LocalDate, LocalTime, LocalDateTime, Instant都是实现相同的接口,这里以LocalDate为例分析java8时间api源码,其他的类与LocalDate类似。

  LocalDate的相关类图如下:完整类图

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

可以看出LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口。

java.time包是在jdk8中上添加进来的,jdk8接口有了一些新的特性:接口的默认方法、静态方法和函数式接口

接口的默认方法:使用default 关键字给接口增加非抽象的方法实现,子类可以选择性实现。

静态方法:接口里可以声明静态方法,并且可以实现。

函数式接口:增加@FunctionalInterface 注解,只要这个接口只包含一个抽象方法。

更多描述可以参考Java 8 指南:https://www.cnblogs.com/xkzhangsanx/p/10847284.html

1.TemporalAccessor源码

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

TemporalAccessor是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的只读访问。

这是日期、时间和偏移量对象的基本接口类型。它是由那些可以提供信息的类实现的,比如{@linkplain TemporalField字段}或{@linkplain TemporalQuery查询}。

(1)boolean isSupported(TemporalField field)

检查是否支持指定的字段

(2)default ValueRange range(TemporalField field)

默认方法,获取指定字段的有效值范围

(3)default int get(TemporalField field)

这个方法为默认方法,以int的形式获取指定字段的值

(4)long getLong(TemporalField field)

以long的形式获取指定字段的值

(5)default <R> R query(TemporalQuery<R> query)

默认方法,这个日期-时间查询。它使用指定的查询策略对象查询此日期-时间。

2.Temporal源码

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

Temporal继承TemporalAccessor接口。

Temporal也是框架级接口,定义对时态对象(如日期、时间、偏移量或它们的某些组合)的读写访问。

这是日期、时间和偏移量对象的基本接口类型,这些对象足够完整,可以使用加减操作。

(1)boolean isSupported(TemporalUnit unit)

检查是否支持指定的单元

(2)default Temporal with(TemporalAdjuster adjuster)

默认方法,返回调整后的对象

例如:

date = date.with(lastDayOfMonth());

返回当前月的最后一天

(3)Temporal with(TemporalField field, long newValue)

根据指定的字段更改

(4)default Temporal plus(TemporalAmount amount)

默认方法,增加指定时间

(5)Temporal plus(long amountToAdd, TemporalUnit unit)

根据指定的单位增加时间

(6)default Temporal minus(TemporalAmount amount)

默认方法,减少指定时间

(7)default Temporal minus(long amountToSubtract, TemporalUnit unit)

默认方法,根据指定的单元减少时间

(8)long until(Temporal endExclusive, TemporalUnit unit)

根据指定的单元计算到另一个时间的相差值

例如:

        LocalDate localDate = LocalDate.of(2019, 1, 1);
LocalDate endDate = LocalDate.of(2019, 1, 16);
long days = localDate.until(endDate, ChronoUnit.DAYS);
System.out.println(days);

输出:15

3.TemporalAdjuster源码

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

TemporalAdjuster接口加了函数式接口@FunctionalInterface注解,用于调整时间对象的策略。

(1)Temporal adjustInto(Temporal temporal)

调整指定的时间对象。

java.time.temporal.TemporalAdjusters 为常用的时间调节器,包含当月第一天,最后一天等等。

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

方法说明:

dayOfWeekInMonth   同一个月中每一周的第几天
firstDayOfMonth     当月的第一天
firstDayOfNextMonth   下月的第一天
firstDayOfNextYear   明年的第一天
firstDayOfYear     当年的第一天
firstInMonth          同一个月中,第一个符合星期几要求的值
lastDayOfMonth     当月的最后一天
lastDayOfNextMonth   下月的最后一天
lastDayOfNextYear   明年的最后一天
lastDayOfYear   今年的最后一天
lastInMonth   同一个月中,最后一个符合星期几要求的值
next/previous  将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期
nextOrSame/previousOrSame  将其值设定为日期调整后或者调整前,第一个符合指定星
期几要求的日期,如果该日期已经符合要求,直接返回该对象

例如:当月最后一天

temporal = temporal.with(lastDayOfMonth());

4.ChronoLocalDate源码

ChronoLocalDate 接口 继承了Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>接口。

在任意年表中不包含(时间或时区)的日期,用于高级全球化用例。

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

从图中圈中部分可以看出 ChronoLocalDate实现了实现或重写了Temporal, TemporalAdjuster, Comparable<ChronoLocalDate>接口。

其他方法:

(1)default boolean isLeapYear()

默认方法,计算闰年

(2)int lengthOfMonth()

根据日历系统的定义,返回由这个日期表示的月份的长度。

(3)default int lengthOfYear()

默认方法,返回由日历系统定义的日期表示的年份长度。

(4)default long toEpochDay()

默认方法,返回1970-01-01开始的天数

(5)default int compareTo(ChronoLocalDate other)

默认方法,实现接口Comparable,比较大小

(6)default boolean isAfter(ChronoLocalDate other)

是否在other后面

(7)default boolean isBefore(ChronoLocalDate other)

是否在other前面

(8)default boolean isEqual(ChronoLocalDate other)

是否与other相等

(9)object接口相关的方法:

boolean equals(Object obj)

int hashCode()

String toString()

(10)static ChronoLocalDate from(TemporalAccessor temporal)

从时态对象获取ChronoLocalDate的实例。

(11)default ChronoLocalDateTime<?> atTime(LocalTime localTime)

将这个日期和时间组合起来,创建一个ChronoLocalDateTime。

(12)default String format(DateTimeFormatter formatter)

ChronoLocalDate 格式化处理

(13)Chronology getChronology()

获取此日期的年表

(14)default Era getEra()

获取由年表定义的年代

5.LocalDate源码

LocalDate同时实现了Temporal, TemporalAdjuster, ChronoLocalDate三个接口,是ChronoLocalDate接口国际化的ISO-8601标准实现,final修饰,线程安全,方法特别多,但很有规律。

类图如下:

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

主要属性为:

/**
*最小日期:-999999999-01-01
*/
public static final LocalDate MIN = LocalDate.of(Year.MIN_VALUE, 1, 1); /**
*最d大日期:+999999999-12-31
*/
public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31); /**
*400年周期中的天数
*/
private static final int DAYS_PER_CYCLE = 146097; /**
*从0年到1970年的天数
*/
static final long DAYS_0000_TO_1970 = (DAYS_PER_CYCLE * 5L) - (30L * 365L + 7L);
/**
*年
*/
private final int year;
/**
*月
*/
private final short month;
/**
*日
*/
private final short day;

主要方法,除了实现Temporal, TemporalAdjuster, ChronoLocalDate三个接口还添加了一些特有的方法。所有可以分为6类方法:

(1)创建LocalDate对象方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

例如:创建当前日期:

LocalDate now = LocalDate.now();

源码:可以看出是使用系统默认的Clock创建当前日期的。

    public static LocalDate now() {
return now(Clock.systemDefaultZone());
}

(2)获取属性方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

例如:获取年

int year = now.getYear();

源码:直接获取属性中year

    public int getYear() {
return year;
}

(3)修改属性的方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

例如:修改年,输出:2020-12-26

        LocalDate localDate1 = now.withYear(2020);
System.out.println(localDate1);

源码:可以看到底层,return new LocalDate(year, month, day); 创建了一个新对象。

    public LocalDate withYear(int year) {
if (this.year == year) {
return this;
}
YEAR.checkValidValue(year);
return resolvePreviousValid(year, month, day);
} private static LocalDate resolvePreviousValid(int year, int month, int day) {
switch (month) {
case 2:
day = Math.min(day, IsoChronology.INSTANCE.isLeapYear(year) ? 29 : 28);
break;
case 4:
case 6:
case 9:
case 11:
day = Math.min(day, 30);
break;
}
return new LocalDate(year, month, day);
}

(4)增加或减少日期方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

例如:减少1年,输出:2018-12-26

        LocalDate localDate2 = now.minusYears(1);
System.out.println(localDate2);

源码:可以看出底层使用了:plusYears(-yearsToSubtract),相当于+(-1)

    public LocalDate minusYears(long yearsToSubtract) {
return (yearsToSubtract == Long.MIN_VALUE ? plusYears(Long.MAX_VALUE).plusYears(1) : plusYears(-yearsToSubtract));
}

(5)转换为各类DateTime(LocalDateTime、ZonedDateTime和OffsetDateTime)方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

例如:转为LocalDateTime 输出为:2019-12-26T00:00

        LocalDateTime localDateTime = now.atStartOfDay();
System.out.println(localDateTime);

源码:this为当前的日期,LocalTime.MIDNIGHT为零点时间,组合为为LocalDateTime

    public LocalDateTime atStartOfDay() {
return LocalDateTime.of(this, LocalTime.MIDNIGHT);
}

(6)其他方法主要为实现ChronoLocalDate定义的方法

例如:ChronoLocalDate中定义的判断和比较方法

Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

  

6.总结

  TemporalAccessor主要定义了只读的获取属性方法,Temporal主要定义了修改日期属性和日期加减运算方法,ChronoLocalDate定义了国际化lDate的通用方法,LocalDate是ChronoLocalDate的ISO标准实现,实现了上述所有接口,final修饰,线程安全,方法定义明确,丰富多样,适用广。