高级JAVA开发必备技能:java8 新日期时间API((五)JSR-310:实战+源码分析)(JAVA 小虚竹)

本文主要是介绍高级JAVA开发必备技能:java8 新日期时间API((五)JSR-310:实战+源码分析)(JAVA 小虚竹),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

❤️作者简介:Java领域优质创作者🏆,CSDN博客专家认证🏆
❤️技术活,该赏
❤️点赞 👍 收藏 ⭐再看,养成习惯

大家好,我是小虚竹。之前有粉丝私聊我,问能不能把JAVA8 新的日期时间API(JSR-310)知识点梳理出来。答案是肯定的,谁让我宠粉呢。由于内容偏多(超十万字了),会拆成多篇来写。

闲话就聊到这,请看下面的正文。

使用场景

对JDK8+中的日期时间工具类封装

项目引用

此博文的依据:hutool-5.6.5版本源码

        <dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.6.5</version></dependency>

方法摘要

方法描述
cn.hutool.core.date.LocalDateTimeUtil.now()
当前时间,默认时区
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant)
{@link Instant}转{@link LocalDateTime},使用默认时区
cn.hutool.core.date.LocalDateTimeUtil.ofUTC(java.time.Instant)
{@link Instant}转{@link LocalDateTime},使用UTC时区
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.ZonedDateTime)
{@link ZonedDateTime}转{@link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.time.ZoneId)
{@link Instant}转{@link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.util.TimeZone)
{@link Instant}转{@link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(long)
毫秒转{@link LocalDateTime},使用默认时区

注意:此方法使用默认时区,如果非UTC,会产生时间偏移

cn.hutool.core.date.LocalDateTimeUtil.ofUTC(long)
毫秒转{@link LocalDateTime},使用UTC时区
cn.hutool.core.date.LocalDateTimeUtil.of(long, java.time.ZoneId)
毫秒转{@link LocalDateTime},根据时区不同,结果会产生时间偏移
cn.hutool.core.date.LocalDateTimeUtil.of(long, java.util.TimeZone)
毫秒转{@link LocalDateTime},结果会产生时间偏移
cn.hutool.core.date.LocalDateTimeUtil.of(java.util.Date)
{@link Date}转{@link LocalDateTime},使用默认时区
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.temporal.TemporalAccessor)
{@link TemporalAccessor}转{@link LocalDateTime},使用默认时区
cn.hutool.core.date.LocalDateTimeUtil.ofDate(java.time.temporal.TemporalAccessor)
{@link TemporalAccessor}转{@link LocalDate},使用默认时区
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence)
解析日期时间字符串为{@link LocalDateTime},仅支持yyyy-MM-dd’T’HH:mm:ss格式,例如:2007-12-03T10:15:30
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
解析日期时间字符串为{@link LocalDateTime},格式支持日期时间、日期、时间
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.lang.String)
解析日期时间字符串为{@link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence)
解析日期时间字符串为{@link LocalDate},仅支持yyyy-MM-dd’T’HH:mm:ss格式,例如:2007-12-03T10:15:30
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)
解析日期时间字符串为{@link LocalDate},格式支持日期
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.lang.String)
解析日期字符串为{@link LocalDate}
cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDateTime)
格式化日期时间为yyyy-MM-dd HH:mm:ss格式
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)
格式化日期时间为指定格式
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.lang.String)
格式化日期时间为指定格式
cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDate)
格式化日期时间为yyyy-MM-dd格式
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.time.format.DateTimeFormatter)
格式化日期时间为指定格式
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.lang.String)
格式化日期时间为指定格式
cn.hutool.core.date.LocalDateTimeUtil.offset(java.time.LocalDateTime, long, java.time.temporal.TemporalUnit)
日期偏移,根据field不同加不同值(偏移会修改传入的对象)
cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime)
获取两个日期的差,如果结束时间早于开始时间,获取结果为负。

返回结果为{@link Duration}对象,通过调用toXXX方法返回相差单位

cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime, java.time.temporal.ChronoUnit)
获取两个日期的差,如果结束时间早于开始时间,获取结果为负。

返回结果为时间差的long值

cn.hutool.core.date.LocalDateTimeUtil.betweenPeriod(java.time.LocalDate, java.time.LocalDate)
获取两个日期的表象时间差,如果结束时间早于开始时间,获取结果为负。

比如2011年2月1日,和2021年8月11日,日相差了10天,月相差6月

cn.hutool.core.date.LocalDateTimeUtil.beginOfDay(java.time.LocalDateTime)
修改为一天的开始时间,例如:2020-02-02 00:00:00,000
cn.hutool.core.date.LocalDateTimeUtil.endOfDay(java.time.LocalDateTime)
修改为一天的结束时间,例如:2020-02-02 23:59:59,999
cn.hutool.core.date.LocalDateTimeUtil.toEpochMilli(java.time.temporal.TemporalAccessor)
{@link TemporalAccessor}转换为 时间戳(从1970-01-01T00:00:00Z开始的毫秒数)

方法明细-now()

方法名称:cn.hutool.core.date.LocalDateTimeUtil.now()

方法描述

当前时间,默认时区

支持版本及以上

参数描述:

参数名描述

返回值:

{@link LocalDateTime}

参考案例:

		Assert.assertNotNull(LocalDateTimeUtil.now());System.out.println(LocalDateTimeUtil.now());

image-20210919141925941

源码解析:

/*** 当前时间,默认时区** @return {@link LocalDateTime}*/
public static LocalDateTime now() {return LocalDateTime.now();
}

LocalDateTime.now() 的源码

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

Clock.systemDefaultZone()

用的是系统默认的时区ZoneId.systemDefault()

    public static Clock systemDefaultZone() {return new SystemClock(ZoneId.systemDefault());}

image-2021081495878

最终调用的也是System.currentTimeMillis()

方法明细-of(java.time.Instant)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant)

方法描述

{@link Instant}转{@link LocalDateTime},使用默认时区

支持版本及以上

参数描述:

参数名描述
Instant instant
instant {@link Instant}

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2020-01-23 12:23:56";final DateTime dt = DateUtil.parse(dateStr);LocalDateTime of = LocalDateTimeUtil.of(dt.toInstant());System.out.println(of);

image-20210919143205699

源码解析:

public static LocalDateTime of(Instant instant) {return of(instant, ZoneId.systemDefault());}

这里使用了默认时区,所以打印出来的日期时间是带时区的。

public static LocalDateTime of(Instant instant, ZoneId zoneId) {if (null == instant) {return null;}return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));
}

方法明细-ofUTC(java.time.Instant)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.ofUTC(java.time.Instant)

方法描述

{@link Instant}转{@link LocalDateTime},使用UTC时区

支持版本及以上

参数描述:

参数名描述
Instant instant
instant {@link Instant}

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2020-01-23T12:23:56";final DateTime dt = DateUtil.parse(dateStr);LocalDateTime of = LocalDateTimeUtil.ofUTC(dt.toInstant());Assert.assertEquals(dateStr, of.toString());System.out.println(of);

image-20210919144624993

源码解析:

	public static LocalDateTime ofUTC(Instant instant) {return of(instant, ZoneId.of("UTC"));}

这里使用了UTC 时区,然后调用下面的LocalDateTime.ofInstant

	public static LocalDateTime of(Instant instant, ZoneId zoneId) {if (null == instant) {return null;}return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));}

方法明细-of(java.time.ZonedDateTime)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.time.ZonedDateTime)

方法描述

{@link ZonedDateTime}转{@link LocalDateTime}

支持版本及以上

参数描述:

参数名描述
ZonedDateTime zonedDateTime
zonedDateTime {@link ZonedDateTime}

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-21T11:23:56";final DateTime dt = DateUtil.parse(dateStr);//使用默认时区LocalDateTime localDateTime = LocalDateTimeUtil.of(dt);System.out.println(localDateTime);ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());System.out.println(zonedDateTime);zonedDateTime = localDateTime.atZone( ZoneId.of("Asia/Shanghai"));System.out.println(zonedDateTime);LocalDateTime of = LocalDateTimeUtil.of(zonedDateTime);Assert.assertNotNull(of);Assert.assertEquals("2021-05-21T11:23:56", of.toString());

image-20210919145102122

源码解析:

public static LocalDateTime of(ZonedDateTime zonedDateTime) {if (null == zonedDateTime) {return null;}return zonedDateTime.toLocalDateTime();}

这里先判断了参数 是否空值

然后调用zonedDateTime.toLocalDateTime()

我们知道zonedDateTimeLocalDateTime 是可以直接转化的

方法明细-of(java.time.Instant, java.time.ZoneId)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.time.ZoneId)

方法描述

{@link Instant}转{@link LocalDateTime}

支持版本及以上

参数描述:

参数名描述
Instant instant
instant {@link Instant}
ZoneId zoneId
zoneId 时区

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-21T11:23:56";final DateTime dt = DateUtil.parse(dateStr);LocalDateTime of = LocalDateTimeUtil.of(dt.getTime(), ZoneId.of("UTC"));Assert.assertNotNull(of);Assert.assertEquals(dateStr, of.toString());of = LocalDateTimeUtil.of(dt.getTime(), ZoneId.of("Asia/Shanghai"));Assert.assertNotNull(of);Assert.assertEquals("2021-05-21T19:23:56", of.toString());

源码解析:

	public static LocalDateTime of(Instant instant, ZoneId zoneId) {if (null == instant) {return null;}return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));}

这里先判断了参数 是否空值

然后执行了LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()))

这里可拆分两部分:

1、ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault())

2、LocalDateTime.ofInstant(instant, zoneId)

ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()) 的源码

public static <T> T defaultIfNull(final T object, final T defaultValue) {return (null != object) ? object : defaultValue;}

这个很好理解,判断值是否为null ,如果是返回默认值,如果不是,原值返回。

**LocalDateTime.ofInstant(instant, zoneId) ** 是jdk8自带的源生方法

方法明细-of(java.time.Instant, java.util.TimeZone)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.util.TimeZone)

方法描述

{@link Instant}转{@link LocalDateTime}

支持版本及以上

参数描述:

参数名描述
Instant instant
instant {@link Instant}
TimeZone timeZone
timeZone 时区

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-21T11:23:56";// 通过转换获取的Instant为UTC时间Instant instant1 = DateUtil.parse(dateStr).toInstant();LocalDateTime localDateTime = LocalDateTimeUtil.of(instant1,TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));Assert.assertEquals("2021-05-21T19:23:56", localDateTime.toString());System.out.println(localDateTime);

image-20210919150621318

源码解析:

	public static LocalDateTime of(Instant instant, TimeZone timeZone) {if (null == instant) {return null;}return of(instant, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId());}

这里先判断了参数 是否空值

然后执行了LocalDateTime.ofInstant(timeZone, zoneId)

这里可拆分两部分:

1、ObjectUtil.defaultIfNull(timeZone, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId())

2、LocalDateTime.ofInstant(timeZone, zoneId)

ObjectUtil.defaultIfNull(timeZone, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId()) 的源码

	public static <T> T defaultIfNull(final T object, final T defaultValue) {return (null != object) ? object : defaultValue;}

这个很好理解,判断值是否为null ,如果是返回默认值,如果不是,原值返回。

**LocalDateTime.ofInstant(instant, zoneId) ** 是jdk8自带的源生方法

方法明细-of(long)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(long)

方法描述

毫秒转{@link LocalDateTime},使用默认时区

注意:此方法使用默认时区,如果非UTC,会产生时间偏移

支持版本及以上

参数描述:

参数名描述
long epochMilli
epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-22 10:23:56";Long time = DateUtil.parse(dateStr).getTime();// 使用默认时区LocalDateTime localDateTime = LocalDateTimeUtil.of(time);Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());System.out.println(localDateTime);

image-20210919151333112

源码解析:

	public static LocalDateTime of(long epochMilli) {return of(Instant.ofEpochMilli(epochMilli));}

这是把long转成Instant

public static Instant ofEpochMilli(long epochMilli) {long secs = Math.floorDiv(epochMilli, 1000);int mos = (int)Math.floorMod(epochMilli, 1000);return create(secs, mos * 1000_000);}

然后再调用of(Instant)

public static LocalDateTime of(Instant instant) {return of(instant, ZoneId.systemDefault());
}

方法明细-ofUTC(long)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.ofUTC(long)

方法描述

毫秒转{@link LocalDateTime},使用UTC时区

支持版本及以上

参数描述:

参数名描述
long epochMilli
epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-22T10:23:56";Long time = DateUtil.parse(dateStr).getTime();// 使用UTC时区LocalDateTime localDateTime = LocalDateTimeUtil.ofUTC(time);Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());System.out.println(localDateTime);

image-20210919152034372

源码解析:

public static LocalDateTime ofUTC(long epochMilli) {return ofUTC(Instant.ofEpochMilli(epochMilli));}

这是把long转成Instant

public static Instant ofEpochMilli(long epochMilli) {long secs = Math.floorDiv(epochMilli, 1000);int mos = (int)Math.floorMod(epochMilli, 1000);return create(secs, mos * 1000_000);}

然后再调用ofUTC(Instant)

public static LocalDateTime ofUTC(Instant instant) {return of(instant, ZoneId.of("UTC"));}

方法明细-of(long, java.time.ZoneId)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(long, java.time.ZoneId)

方法描述

毫秒转{@link LocalDateTime},根据时区不同,结果会产生时间偏移

支持版本及以上

参数描述:

参数名描述
long epochMilli
epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
ZoneId zoneId
zoneId 时区

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-22T10:23:56";Long time = DateUtil.parse(dateStr).getTime();LocalDateTime localDateTime = LocalDateTimeUtil.of(time,ZoneId.of("Asia/Shanghai"));Assert.assertEquals("2021-05-22T18:23:56", localDateTime.toString());

源码解析:

/*** 毫秒转{@link LocalDateTime},根据时区不同,结果会产生时间偏移** @param epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数* @param zoneId     时区* @return {@link LocalDateTime}*/public static LocalDateTime of(long epochMilli, ZoneId zoneId) {return of(Instant.ofEpochMilli(epochMilli), zoneId);}

这是把long转成Instant

public static Instant ofEpochMilli(long epochMilli) {long secs = Math.floorDiv(epochMilli, 1000);int mos = (int)Math.floorMod(epochMilli, 1000);return create(secs, mos * 1000_000);}

然后再调用of(Instant, zoneId)

上面的方法已经分析多次,就不再重复水字数。

方法明细-of(long, java.util.TimeZone)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(long, java.util.TimeZone)

方法描述

毫秒转{@link LocalDateTime},结果会产生时间偏移

支持版本及以上

参数描述:

参数名描述
long epochMilli
epochMilli 从1970-01-01T00:00:00Z开始计数的毫秒数
TimeZone timeZone
timeZone 时区

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-22T10:23:56";Long time = DateUtil.parse(dateStr).getTime();LocalDateTime localDateTime = LocalDateTimeUtil.of(time, TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));Assert.assertEquals("2021-05-22T18:23:56", localDateTime.toString());

源码解析:

public static LocalDateTime of(long epochMilli, TimeZone timeZone) {return of(Instant.ofEpochMilli(epochMilli), timeZone);}

这是把long转成Instant

public static Instant ofEpochMilli(long epochMilli) {long secs = Math.floorDiv(epochMilli, 1000);int mos = (int)Math.floorMod(epochMilli, 1000);return create(secs, mos * 1000_000);}

然后再调用of(Instant, timeZone)

上面的方法已经分析多次,就不再重复水字数。

方法明细-of(java.util.Date)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.util.Date)

方法描述

{@link Date}转{@link LocalDateTime},使用默认时区

支持版本及以上

参数描述:

参数名描述
Date date
date Date对象

返回值:

{@link LocalDateTime}

参考案例:

	String dateStr = "2021-05-22 10:23:56";DateTime date = DateUtil.parse(dateStr);//使用默认时区LocalDateTime localDateTime = LocalDateTimeUtil.of(date);Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());

源码解析:

	public static LocalDateTime of(Date date) {if (null == date) {return null;}if (date instanceof DateTime) {return of(date.toInstant(), ((DateTime) date).getZoneId());}return of(date.toInstant());}

此方法是把Date 强转为LocalDateTime

好习惯,先判断参数date是否为空

if (date instanceof DateTime) {return of(date.toInstant(), ((DateTime) date).getZoneId());}

这个DateTime 是hutool自己封装的对象,继承于Date ,封装了一些常用的方法

image-20210919153217935

如果不是前两者的话,就调用of(date.Instant)

方法明细-of(java.time.temporal.TemporalAccessor)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.of(java.time.temporal.TemporalAccessor)

方法描述

{@link TemporalAccessor}转{@link LocalDateTime},使用默认时区

支持版本及以上

参数描述:

参数名描述
TemporalAccessor temporalAccessor
temporalAccessor {@link TemporalAccessor}

返回值:

{@link LocalDateTime}

参考案例:

		String dateStr = "2021-05-22T10:23:56";//使用默认时区TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_DATE_TIME.parse(dateStr);LocalDateTime localDateTime = LocalDateTimeUtil.of(temporalAccessor);Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());

源码解析:

	public static LocalDateTime of(TemporalAccessor temporalAccessor) {if (null == temporalAccessor) {return null;}if(temporalAccessor instanceof LocalDate){return ((LocalDate)temporalAccessor).atStartOfDay();}return LocalDateTime.of(TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH),TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY),TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND));}

因为入参TemporalAccessor time的实现类常用的有如下几个(java8提供的):

  • LocalDateTime
  • LocalDate
  • LocalTime

好习惯,先判断参数temporalAccessor是否为空

然后判断temporalAccessor是否为LocalDate对象,如果是则调用LocalDate.atStartOfDay(),返回值是localDate+‘00:00’

//LocalDate
public LocalDateTime atStartOfDay() {return LocalDateTime.of(this, LocalTime.MIDNIGHT);}
/*** The time of midnight at the start of the day, '00:00'.*/
public static final LocalTime MIDNIGHT;
public static LocalDateTime of(LocalDate date, LocalTime time) {Objects.requireNonNull(date, "date");Objects.requireNonNull(time, "time");return new LocalDateTime(date, time);
}

最后通过LocalDateTime.of 方法获取LocalDateTime对象的值。

但是博主发现一个问题,LocalTime 是没有年月日的,那怎么转化为LocalDateTime ,我们来写个demo看看效果

LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTimeUtil.of(localTime);
System.out.println(localDateTime);

image-20210919154701692

居然没有报错,这是为什么呢

return LocalDateTime.of(TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH),TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY),TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND));

这里也是hutool自己封装的方法,都是调用**public static int get(TemporalAccessor temporalAccessor, TemporalField field) ** 源码如下

public static int get(TemporalAccessor temporalAccessor, TemporalField field) {if (temporalAccessor.isSupported(field)) {return temporalAccessor.get(field);}return (int)field.range().getMinimum();
}

这个代码很好理解,就是取temporalAccessor 对象对应的属性值,如果不存在,则取这个属性值的最小值。

断点看效果:

1、localtime是不存在year属性的

image-20210919155438622

2、取这个字段的最小值。

image-20210919155550186

其他字段获取方式也差不多。

方法明细-ofDate(java.time.temporal.TemporalAccessor)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.ofDate(java.time.temporal.TemporalAccessor)

方法描述

{@link TemporalAccessor}转{@link LocalDate},使用默认时区

支持版本及以上

5.3.10

参数描述:

参数名描述
TemporalAccessor temporalAccessor
temporalAccessor {@link TemporalAccessor}

返回值:

{@link LocalDate}

参考案例:

		String dateStr = "2021-05-22T10:23:56";//使用默认时区TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_DATE_TIME.parse(dateStr);LocalDate localDate = LocalDateTimeUtil.ofDate(temporalAccessor);Assert.assertEquals("2021-05-22", localDate.toString());

源码解析:

	public static LocalDate ofDate(TemporalAccessor temporalAccessor) {if (null == temporalAccessor) {return null;}if(temporalAccessor instanceof LocalDateTime){return ((LocalDateTime)temporalAccessor).toLocalDate();}return LocalDate.of(TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH));}

因为入参TemporalAccessor time的实现类常用的有如下几个(java8提供的):

  • LocalDateTime
  • LocalDate
  • LocalTime

好习惯,先判断参数temporalAccessor是否为空

然后判断temporalAccessor是否为LocalDateTime对象,如果是则调用LocalDateTime.toLocalDate(),返回值是localDate,因为LocalDateTime=localDate+LocalTime

最后通过LocalDate.of 方法获取LocalDate对象的值。

方法明细-parse(java.lang.CharSequence)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence)

方法描述

解析日期时间字符串为{@link LocalDateTime},仅支持yyyy-MM-dd’T’HH:mm:ss格式,例如:2007-12-03T10:15:30

支持版本及以上

参数描述:

参数名描述
CharSequence text
text 日期时间字符串

返回值:

{@link LocalDateTime}

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());

image-20210919160344393

源码解析:

	/*** 解析日期时间字符串为{@link LocalDateTime},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30** @param text      日期时间字符串* @return {@link LocalDateTime}*/public static LocalDateTime parse(CharSequence text) {return parse(text, (DateTimeFormatter)null);}

请看下面的源码分析。

方法明细-parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)

方法描述

解析日期时间字符串为{@link LocalDateTime},格式支持日期时间、日期、时间

支持版本及以上

参数描述:

参数名描述
CharSequence text
text 日期时间字符串 当formatter为null时,字符串要符合格式2020-01-23T12:23:56
DateTimeFormatter formatter
formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}

返回值:

{@link LocalDateTime}

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());System.out.println(localDateTime);

image-20210919160344393

源码解析:

	public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {if (null == text) {return null;}if (null == formatter) {return LocalDateTime.parse(text);}return of(formatter.parse(text));}

如果有同学对CharSequence 对象陌生的话,那对String 应该不会陌生,StringCharSequence 的实现接口

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {...}

DateTimeFormatter 是jdk8提供的日期时间格式化器,用来替换我们的老朋友 simpledateformat

好习惯,先判断参数CharSequence是否为空

然后再判断参数DateTimeFormatter 是否为空,如果为空,则直接调用LocalDateTime.parse(text)

来看看源码

public static LocalDateTime parse(CharSequence text) {return parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

这里用的日期格式化字符串要像这种格式的:

such as ‘2011-12-03T10:15:30’

那如果传入的CharSequence参数不是这种格式的字符串,会是什么结果

//符合格式2020-01-23T12:23:56
LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);
Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());
System.out.println(localDateTime);//不符合格式的
DateTimeFormatter dateTimeFormatter = null;
localDateTime = LocalDateTimeUtil.parse("2020-01-23", dateTimeFormatter);
System.out.println(localDateTime);

执行结果,在预料之中,直接报错,这里是个坑,大家要注意

java.time.format.DateTimeParseException: Text ‘2020-01-23’ could not be parsed at index 10

image-20210919161934470

最后调用of(formatter.parse(text))

formatter.parse(text) 返回结果是TemporalAccessor,不一定是我们想要的LocalDateTime ,所以还要再通过of转一下

formatter.parse(text) 是原生JDK8自带的方法。

方法明细-parse(java.lang.CharSequence, java.lang.String)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.lang.String)

方法描述

解析日期时间字符串为{@link LocalDateTime}

支持版本及以上

参数描述:

参数名描述
CharSequence text
text 日期时间字符串
String format
format 日期格式,类似于yyyy-MM-dd HH:mm:ss,SSS

返回值:

{@link LocalDateTime}

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN);Assert.assertEquals("2020-01-23T00:00", localDateTime.toString());

源码解析:

	public static LocalDateTime parse(CharSequence text, String format) {if (null == text) {return null;}DateTimeFormatter formatter = null;if(StrUtil.isNotBlank(format)){// 修复yyyyMMddHHmmssSSS格式不能解析的问题// fix issue#1082//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085if(StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)){final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);if(ReUtil.isMatch("[S]{1,2}", fraction)){//将yyyyMMddHHmmssS、yyyyMMddHHmmssSS的日期统一替换为yyyyMMddHHmmssSSS格式,用0补text += StrUtil.repeat('0', 3-fraction.length());}formatter = new DateTimeFormatterBuilder().appendPattern(DatePattern.PURE_DATETIME_PATTERN).appendValue(ChronoField.MILLI_OF_SECOND, 3).toFormatter();} else{formatter = DateTimeFormatter.ofPattern(format);}}return parse(text, formatter);}

养成好习惯,先判断参数CharSequence和format是否为空

这边针对jdk8的一个bug进行了兼容处理

1、在正常配置按照标准格式的字符串日期,是能够正常转换的。如果月,日,时,分,秒在不足两位的情况需要补0,否则的话会转换失败,抛出异常。
		DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");LocalDateTime dt1 = LocalDateTime.parse("2021-7-20 23:46:43.946", DATE_TIME_FORMATTER);System.out.println(dt1);

会报错:

image-202107208183

java.time.format.DateTimeParseException: Text '2021-7-20 23:46:43.946' could not be parsed at index 5

分析原因:是格式字符串与实际的时间不匹配

“yyyy-MM-dd HH:mm:ss.SSS”

“2021-7-20 23:46:43.946”

中间的月份格式是MM,实际时间是7

解决方案:保持格式字符串与实际的时间匹配

	DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");LocalDateTime dt1 = LocalDateTime.parse("2021-07-20 23:46:43.946", DATE_TIME_FORMATTER);System.out.println(dt1);

image-20210720504067

方法明细-parseDate(java.lang.CharSequence)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence)

方法描述

解析日期时间字符串为{@link LocalDate},仅支持yyyy-MM-dd’T’HH:mm:ss格式,例如:2007-12-03T10:15:30

支持版本及以上

5.3.10

参数描述:

参数名描述
CharSequence text
text 日期时间字符串

返回值:

{@link LocalDate}

参考案例:

		LocalDate localDate = LocalDateTimeUtil.parseDate("2020-01-23");		Assert.assertEquals("2020-01-23", localDate.toString());

源码解析:

	/*** 解析日期时间字符串为{@link LocalDate},仅支持yyyy-MM-dd'T'HH:mm:ss格式,例如:2007-12-03T10:15:30** @param text      日期时间字符串* @return {@link LocalDate}* @since 5.3.10*/public static LocalDate parseDate(CharSequence text) {return parseDate(text, (DateTimeFormatter)null);}

请看下面的源码分析。

方法明细-parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)

方法描述

解析日期时间字符串为{@link LocalDate},格式支持日期

支持版本及以上

5.3.10

参数描述:

参数名描述
CharSequence text
text 日期时间字符串
DateTimeFormatter formatter
formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}

返回值:

{@link LocalDate}

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("12:23:56", DatePattern.NORM_TIME_PATTERN);Assert.assertEquals("12:23:56", localDateTime.toLocalTime().toString());

源码解析:

	public static LocalDate parseDate(CharSequence text, DateTimeFormatter formatter) {if (null == text) {return null;}if (null == formatter) {return LocalDate.parse(text);}return ofDate(formatter.parse(text));}

如果有同学对CharSequence 对象陌生的话,那对String 应该不会陌生,StringCharSequence 的实现接口

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {...}

DateTimeFormatter 是jdk8提供的日期时间格式化器,用来替换我们的老朋友 simpledateformat

好习惯,先判断参数CharSequence是否为空

然后再判断参数DateTimeFormatter 是否为空,如果为空,则直接调用LocalDate.parse(text)

来看看源码

 public static LocalDate parse(CharSequence text) {return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);}

这里用的日期格式化字符串要像这种格式的:

such as ‘2011-12-03’

最后调用of(formatter.parse(text))

formatter.parse(text) 返回结果是TemporalAccessor,不一定是我们想要的LocalDate ,所以还要再通过of转一下

formatter.parse(text) 是原生JDK8自带的方法。

方法明细-parseDate(java.lang.CharSequence, java.lang.String)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.lang.String)

方法描述

解析日期字符串为{@link LocalDate}

支持版本及以上

参数描述:

参数名描述
CharSequence text
text 日期字符串
String format
format 日期格式,类似于yyyy-MM-dd

返回值:

{@link LocalDateTime}

参考案例:

		//第一个参数和第二个参数格式保持一致LocalDate localDate = LocalDateTimeUtil.parseDate("2020-01-23 12:23:56","yyyy-MM-dd hh:mm:ss");Assert.assertEquals("2020-01-23", localDate.toString());localDate = LocalDateTimeUtil.parseDate("2020/01/23 12:23:56","yyyy/MM/dd hh:mm:ss");Assert.assertEquals("2020-01-23", localDate.toString());

源码解析:

	public static LocalDate parseDate(CharSequence text, String format) {if (null == text) {return null;}return parseDate(text, DateTimeFormatter.ofPattern(format));}

请看上面的源码分析。

方法明细-formatNormal(java.time.LocalDateTime)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDateTime)

方法描述

格式化日期时间为yyyy-MM-dd HH:mm:ss格式

支持版本及以上

5.3.11

参数描述:

参数名描述
LocalDateTime time
time {@link LocalDateTime}

返回值:

格式化后的字符串

参考案例:

        final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");String	format = LocalDateTimeUtil.formatNormal(localDateTime);Assert.assertEquals("2020-01-23 12:23:56", format);

源码解析:

	/*** 格式化日期时间为yyyy-MM-dd HH:mm:ss格式** @param time      {@link LocalDateTime}* @return 格式化后的字符串* @since 5.3.11*/public static String formatNormal(LocalDateTime time) {return format(time, DatePattern.NORM_DATETIME_FORMATTER);}//------------------------------
public static String format(LocalDateTime time, DateTimeFormatter formatter) {return TemporalAccessorUtil.format(time, formatter);}

TemporalAccessorUtil 类是hutool封装的工具类,看下面的源码,也是比较好理解的。

//TemporalAccessorUtil
/*** 格式化日期时间为指定格式** @param time      {@link TemporalAccessor}* @param formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}* @return 格式化后的字符串* @since 5.3.10*/
public static String format(TemporalAccessor time, DateTimeFormatter formatter) {if (null == time) {return null;}if(null == formatter){formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;}try {return formatter.format(time);} catch (UnsupportedTemporalTypeException e){if(time instanceof LocalDate && e.getMessage().contains("HourOfDay")){// 用户传入LocalDate,但是要求格式化带有时间部分,转换为LocalDateTime重试return formatter.format(((LocalDate) time).atStartOfDay());}else if(time instanceof LocalTime && e.getMessage().contains("YearOfEra")){// 用户传入LocalTime,但是要求格式化带有日期部分,转换为LocalDateTime重试return formatter.format(((LocalTime) time).atDate(LocalDate.now()));}throw e;}
}

养成好习惯,先判断参数TemporalAccessorDateTimeFormatter 是否为空

如果DateTimeFormatter 为空,则给默认值DateTimeFormatter.ISO_LOCAL_DATE_TIME

such as ‘2011-12-03T10:15:30’

然后调用格式化方法formatter.format(time) 如果time 不是LocalDateTime 对象,则会报错,然后在catch里做了兼容处理,对LocalDateLocalTime 对象可以进行格式化处理,其他的直接返回异常。

方法明细-format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)

方法描述

格式化日期时间为指定格式

支持版本及以上

参数描述:

参数名描述
LocalDateTime time
time {@link LocalDateTime}
DateTimeFormatter formatter
formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}

返回值:

格式化后的字符串

参考案例:

		LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");String format = LocalDateTimeUtil.format(localDateTime, DateTimeFormatter.ISO_DATE_TIME);Assert.assertEquals("2020-01-23T12:23:56", format);

源码解析:

	/*** 格式化日期时间为指定格式** @param time      {@link LocalDateTime}* @param formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}* @return 格式化后的字符串*/public static String format(LocalDateTime time, DateTimeFormatter formatter) {return TemporalAccessorUtil.format(time, formatter);}

请看上面的源码分析。

方法明细-format(java.time.LocalDateTime, java.lang.String)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.lang.String)

方法描述

格式化日期时间为指定格式

支持版本及以上

参数描述:

参数名描述
LocalDateTime time
time {@link LocalDateTime}
String format
format 日期格式,类似于yyyy-MM-dd HH:mm:ss,SSS

返回值:

格式化后的字符串

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");String format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_PATTERN);Assert.assertEquals("2020-01-23 12:23:56", format);

源码解析:

	public static String format(LocalDateTime time, String format) {if (null == time) {return null;}return format(time, DateTimeFormatter.ofPattern(format));}

DateTimeFormatter.ofPattern(format) 执行完会返回DateTimeFormatter

然后会调用 format(time, DateTimeFormatter 方法

请看上面的源码分析。

方法明细-formatNormal(java.time.LocalDate)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDate)

方法描述

格式化日期时间为yyyy-MM-dd格式

支持版本及以上

5.3.11

参数描述:

参数名描述
LocalDate date
date {@link LocalDate}

返回值:

格式化后的字符串

参考案例:

		final LocalDate date = LocalDate.parse("2020-01-23");String format = LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);Assert.assertEquals("2020-01-23", format);format = LocalDateTimeUtil.formatNormal(date);Assert.assertEquals("2020-01-23", format);

源码解析:

public static String formatNormal(LocalDate date) {return format(date, DatePattern.NORM_DATE_FORMATTER);}

请看上面的源码分析。

方法明细-format(java.time.LocalDate, java.time.format.DateTimeFormatter)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.time.format.DateTimeFormatter)

方法描述

格式化日期时间为指定格式

支持版本及以上

5.3.10

参数描述:

参数名描述
LocalDate date
date {@link LocalDate}
DateTimeFormatter formatter
formatter 日期格式化器,预定义的格式见:{@link DateTimeFormatter}

返回值:

格式化后的字符串

参考案例:

		final LocalDate date = LocalDate.parse("2021-05-22");String format = LocalDateTimeUtil.format(date, DateTimeFormatter.ISO_DATE);Assert.assertEquals("2021-05-22", format);

源码解析:

	public static String format(LocalDate date, DateTimeFormatter formatter) {return TemporalAccessorUtil.format(date, formatter);}

请看上面的源码分析。

方法明细-format(java.time.LocalDate, java.lang.String)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.lang.String)

方法描述

格式化日期时间为指定格式

支持版本及以上

5.3.10

参数描述:

参数名描述
LocalDate date
date {@link LocalDate}
String format
format 日期格式,类似于yyyy-MM-dd

返回值:

格式化后的字符串

参考案例:

		final LocalDate date = LocalDate.parse("2020-01-23");String format = LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);Assert.assertEquals("2020-01-23", format);

源码解析:

	public static String format(LocalDate date, String format) {if (null == date) {return null;}return format(date, DateTimeFormatter.ofPattern(format));}

请看上面的源码分析。

方法明细-offset(java.time.LocalDateTime, long, java.time.temporal.TemporalUnit)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.offset(java.time.LocalDateTime, long, java.time.temporal.TemporalUnit)

方法描述

日期偏移,根据field不同加不同值(偏移会修改传入的对象)

支持版本及以上

参数描述:

参数名描述
LocalDateTime time
time {@link LocalDateTime}
long number
number 偏移量,正数为向后偏移,负数为向前偏移
TemporalUnit field
field 偏移单位,见{@link ChronoUnit},不能为null

返回值:

偏移后的日期时间

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);// 非同一对象Assert.assertNotSame(localDateTime, offset);Assert.assertEquals("2020-01-24T12:23:56", offset.toString());

源码解析:

	/*** 日期偏移,根据field不同加不同值(偏移会修改传入的对象)** @param time   {@link LocalDateTime}* @param number 偏移量,正数为向后偏移,负数为向前偏移* @param field  偏移单位,见{@link ChronoUnit},不能为null* @return 偏移后的日期时间*/public static LocalDateTime offset(LocalDateTime time, long number, TemporalUnit field) {if (null == time) {return null;}return time.plus(number, field);}

time.plus(number, field) 是jdk8提供的方法

	LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 30, 23, 14, 20);LocalDateTime offset = localDateTime.plus(1, ChronoUnit.DAYS);// 非同一对象Assert.assertNotSame(localDateTime, offset);System.out.println(offset);

image-20210831233938785

方法明细-between(java.time.LocalDateTime, java.time.LocalDateTime)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime)

方法描述

获取两个日期的差,如果结束时间早于开始时间,获取结果为负。

返回结果为{@link Duration}对象,通过调用toXXX方法返回相差单位 ## 支持版本及以上

参数描述:

参数名描述
LocalDateTime startTimeInclude
startTimeInclude 开始时间(包含)
LocalDateTime endTimeExclude
endTimeExclude 结束时间(不包含)

返回值:

时间差 {@link Duration}对象

参考案例:

		final Duration between = LocalDateTimeUtil.between(LocalDateTimeUtil.parse("2019-02-02T00:00:00"),LocalDateTimeUtil.parse("2020-02-02T00:00:00"));Assert.assertEquals(365, between.toDays());

源码解析:

	public static Duration between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude) {return TemporalUtil.between(startTimeInclude, endTimeExclude);}

其中TemporalUtil 是hutool封装的工具类,源码如下:

/*** 获取两个日期的差,如果结束时间早于开始时间,获取结果为负。* <p>* 返回结果为{@link Duration}对象,通过调用toXXX方法返回相差单位** @param startTimeInclude 开始时间(包含)* @param endTimeExclude   结束时间(不包含)* @return 时间差 {@link Duration}对象*/
public static Duration between(Temporal startTimeInclude, Temporal endTimeExclude) {return Duration.between(startTimeInclude, endTimeExclude);
}

Duration 适合处理较短的时间,需要更高的精确性。我们能使用between()方法比较两个瞬间的差。

Duration.between 是JDK8提供的方法。

方法明细-between(java.time.LocalDateTime, java.time.LocalDateTime, java.time.temporal.ChronoUnit)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime, java.time.temporal.ChronoUnit)

方法描述

获取两个日期的差,如果结束时间早于开始时间,获取结果为负。

返回结果为时间差的long值

支持版本及以上

5.4.5

参数描述:

参数名描述
LocalDateTime startTimeInclude
startTimeInclude 开始时间(包括)
LocalDateTime endTimeExclude
endTimeExclude 结束时间(不包括)
ChronoUnit unit
unit 时间差单位

返回值:

时间差

参考案例:

		final long betweenWeek = DateUtil.betweenWeek(DateUtil.parse("2020-11-21"),DateUtil.parse("2020-11-23"), false);final long betweenWeek2 = LocalDateTimeUtil.between(LocalDateTimeUtil.parse("2020-11-21", "yyy-MM-dd"),LocalDateTimeUtil.parse("2020-11-23", "yyy-MM-dd"),ChronoUnit.WEEKS);Assert.assertEquals(betweenWeek, betweenWeek2);

源码解析:

public static long between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude, ChronoUnit unit) {return TemporalUtil.between(startTimeInclude, endTimeExclude, unit);}

多了一个时间单位的选项

public static long between(Temporal startTimeInclude, Temporal endTimeExclude, ChronoUnit unit) {return unit.between(startTimeInclude, endTimeExclude);
}

这个返回的数据为0

image-20210919181335622

这个返回的数据为1

image-20210919181709928

这两个demo的数据,反应出了结果是按时间差单位来产生的。

方法明细-betweenPeriod(java.time.LocalDate, java.time.LocalDate)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.betweenPeriod(java.time.LocalDate, java.time.LocalDate)

方法描述

获取两个日期的表象时间差,如果结束时间早于开始时间,获取结果为负。

比如2011年2月1日,和2021年8月11日,日相差了10天,月相差6月

支持版本及以上

5.4.5

参数描述:

参数名描述
LocalDate startTimeInclude
startTimeInclude 开始时间(包括)
LocalDate endTimeExclude
endTimeExclude 结束时间(不包括)

返回值:

时间差

参考案例:

		final LocalDate localDate1= LocalDate.parse("2021-05-22");final LocalDate localDate2= LocalDate.parse("2021-06-23");Period period = LocalDateTimeUtil.betweenPeriod(localDate1,localDate2);Assert.assertEquals(1, period.getMonths());Assert.assertEquals(1, period.getDays());period = LocalDateTimeUtil.betweenPeriod(localDate2,localDate1);Assert.assertEquals(-1, period.getMonths());Assert.assertEquals(-1, period.getDays());final LocalDate localDate3= LocalDate.parse("2021-06-22");period = LocalDateTimeUtil.betweenPeriod(localDate1,localDate3);Assert.assertEquals(1, period.getMonths());Assert.assertEquals(0, period.getDays());

源码解析:

public static Period betweenPeriod(LocalDate startTimeInclude, LocalDate endTimeExclude) {return Period.between(startTimeInclude, endTimeExclude);}

Period.between 是JDK8提供的方法

PeriodChronoPeriod 的实现类,类里包含两个变量years ,monthsdays ,所以Period 是由年,月和日组成的时间量。

	LocalDate first = LocalDate.of(2021, 8, 29);LocalDate second = LocalDate.of(2022, 9, 30);Period period = Period.between(first, second);System.out.println(period);

image-20210830224610563

方法明细-beginOfDay(java.time.LocalDateTime)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.beginOfDay(java.time.LocalDateTime)

方法描述

修改为一天的开始时间,例如:2020-02-02 00:00:00,000

支持版本及以上

参数描述:

参数名描述
LocalDateTime time
time 日期时间

返回值:

一天的开始时间

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");final LocalDateTime beginOfDay = LocalDateTimeUtil.beginOfDay(localDateTime);Assert.assertEquals("2020-01-23T00:00", beginOfDay.toString());

源码解析:

/*** 修改为一天的开始时间,例如:2020-02-02 00:00:00,000** @param time 日期时间* @return 一天的开始时间*/public static LocalDateTime beginOfDay(LocalDateTime time) {return time.with(LocalTime.MIN);}

LocalDateTime.with 是jdk8提供的方法。

日期时间的加减法及修改

	LocalDateTime currentTime = LocalDateTime.now(); // 当前日期和时间System.out.println("------------------时间的加减法及修改-----------------------");//3.LocalDateTime的加减法包含了LocalDate和LocalTime的所有加减,上面说过,这里就只做简单介绍System.out.println("3.当前时间:" + currentTime);System.out.println("3.当前时间加5年:" + currentTime.plusYears(5));System.out.println("3.当前时间加2个月:" + currentTime.plusMonths(2));System.out.println("3.当前时间减2天:" + currentTime.minusDays(2));System.out.println("3.当前时间减5个小时:" + currentTime.minusHours(5));System.out.println("3.当前时间加5分钟:" + currentTime.plusMinutes(5));System.out.println("3.当前时间加20秒:" + currentTime.plusSeconds(20));//还可以灵活运用比如:向后加一年,向前减一天,向后加2个小时,向前减5分钟,可以进行连写System.out.println("3.同时修改(向后加一年,向前减一天,向后加2个小时,向前减5分钟):" + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));System.out.println("3.修改年为2025年:" + currentTime.withYear(2025));System.out.println("3.修改月为12月:" + currentTime.withMonth(12));System.out.println("3.修改日为27日:" + currentTime.withDayOfMonth(27));System.out.println("3.修改小时为12:" + currentTime.withHour(12));System.out.println("3.修改分钟为12:" + currentTime.withMinute(12));System.out.println("3.修改秒为12:" + currentTime.withSecond(12));

image-20210714941902

方法明细-endOfDay(java.time.LocalDateTime)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.endOfDay(java.time.LocalDateTime)

方法描述

修改为一天的结束时间,例如:2020-02-02 23:59:59,999

支持版本及以上

参数描述:

参数名描述
LocalDateTime time
time 日期时间

返回值:

一天的结束时间

参考案例:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");final LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(localDateTime);Assert.assertEquals("2020-01-23T23:59:59.999999999", endOfDay.toString());

源码解析:

	/*** 修改为一天的结束时间,例如:2020-02-02 23:59:59,999** @param time 日期时间* @return 一天的结束时间*/public static LocalDateTime endOfDay(LocalDateTime time) {return time.with(LocalTime.MAX);}

请看上面的源码分析。

方法明细-toEpochMilli(java.time.temporal.TemporalAccessor)

方法名称:cn.hutool.core.date.LocalDateTimeUtil.toEpochMilli(java.time.temporal.TemporalAccessor)

方法描述

{@link TemporalAccessor}转换为 时间戳(从1970-01-01T00:00:00Z开始的毫秒数)

支持版本及以上

5.4.1

参数描述:

参数名描述
TemporalAccessor temporalAccessor
temporalAccessor Date对象

返回值:

{@link Instant}对象

参考案例:

		String dateStr = "2021-05-22";//TemporalAccessor 的实现类包含Instant LocalDateTime ZonedDateTime OffsetDateTime LocalDate LocalTime OffsetTimeLocalDate localDate = LocalDate.parse(dateStr);//Date对象long time = LocalDateTimeUtil.toEpochMilli(localDate);Assert.assertEquals(DateUtil.parse(dateStr).getTime(), time);

源码解析:

public static long toEpochMilli(TemporalAccessor temporalAccessor) {return TemporalAccessorUtil.toEpochMilli(temporalAccessor);}

TemporalAccessorUtil.toEpochMilli(temporalAccessor) 是hutool封装的方法。

public static long toEpochMilli(TemporalAccessor temporalAccessor) {return toInstant(temporalAccessor).toEpochMilli();
}

temporalAccessor 对象转化为Instant 对象,我们来看下是怎么转化的

public static Instant toInstant(TemporalAccessor temporalAccessor) {if (null == temporalAccessor) {return null;}Instant result;if (temporalAccessor instanceof Instant) {result = (Instant) temporalAccessor;} else if (temporalAccessor instanceof LocalDateTime) {result = ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()).toInstant();} else if (temporalAccessor instanceof ZonedDateTime) {result = ((ZonedDateTime) temporalAccessor).toInstant();} else if (temporalAccessor instanceof OffsetDateTime) {result = ((OffsetDateTime) temporalAccessor).toInstant();} else if (temporalAccessor instanceof LocalDate) {result = ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault()).toInstant();} else if (temporalAccessor instanceof LocalTime) {// 指定本地时间转换 为Instant,取当天日期result = ((LocalTime) temporalAccessor).atDate(LocalDate.now()).atZone(ZoneId.systemDefault()).toInstant();} else if (temporalAccessor instanceof OffsetTime) {// 指定本地时间转换 为Instant,取当天日期result = ((OffsetTime) temporalAccessor).atDate(LocalDate.now()).toInstant();} else {result = Instant.from(temporalAccessor);}return result;
}

就是对应的temporalAccessor 实现类进行处理,从这个源码中,我们可以学到:如何把不同的时间类型转化为Instant 对象。

然后把Instant 对象转化为毫秒级的long数据

	Instant now = Instant.now();System.out.println("now:"+now);System.out.println(now.getEpochSecond()); // 秒System.out.println(now.toEpochMilli()); // 毫秒

image-20210720905353

总结

本文的实战+源码分析只是抛转引玉,实战让大家能知道如何去使用JSR-310 新的日期时间API,源码分析可以让大家知其所以然。

本篇文章 是JSR-310系列的一个里程碑,感谢大家的一路支持,让博主坚持把这个系列的文章写完。

❤️祝大家中秋快乐❤️

推荐相关文章

hutool日期时间系列文章

1DateUtil(时间工具类)-当前时间和当前时间戳

2DateUtil(时间工具类)-常用的时间类型Date,DateTime,Calendar和TemporalAccessor(LocalDateTime)转换

3DateUtil(时间工具类)-获取日期的各种内容

4DateUtil(时间工具类)-格式化时间

5DateUtil(时间工具类)-解析被格式化的时间

6DateUtil(时间工具类)-时间偏移量获取

7DateUtil(时间工具类)-日期计算

8ChineseDate(农历日期工具类)

9LocalDateTimeUtil(JDK8+中的{@link LocalDateTime} 工具类封装)

10TemporalAccessorUtil{@link TemporalAccessor} 工具类封装

其他

要探索JDK的核心底层源码,那必须掌握native用法

万字博文教你搞懂java源码的日期和时间相关用法

java的SimpleDateFormat线程不安全出问题了,虚竹教你多种解决方案

源码分析:JDK获取默认时区的风险和最佳实践

高级JAVA开发必备技能:时区的规则发生变化时,如何同步JDK的时区规则

今天是持续写作的第 12 / 100 天。
可以关注我,点赞我、评论我、收藏我啦。

这篇关于高级JAVA开发必备技能:java8 新日期时间API((五)JSR-310:实战+源码分析)(JAVA 小虚竹)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/466485

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template