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);
源码解析:
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);
源码解析:
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);
源码解析:
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 ,封装了一些常用的方法
如果不是前两者的话,就调用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);
居然没有报错,这是为什么呢
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属性的
2、取这个字段的最小值。
其他字段获取方式也差不多。
方法明细-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());
源码解析:
/\*\*
\* 解析日期时间字符串为{@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);
源码解析:
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 应该不会陌生,String 是CharSequence 的实现接口
public final class String
implements 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
最后调用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-8031085
if(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);
会报错:
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);
方法明细-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 应该不会陌生,String 是CharSequence 的实现接口
public final class String
implements 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;
}
}
养成好习惯,先判断参数TemporalAccessor 和DateTimeFormatter 是否为空
如果DateTimeFormatter 为空,则给默认值DateTimeFormatter.ISO_LOCAL_DATE_TIME
such as ‘2011-12-03T10:15:30’
然后调用格式化方法formatter.format(time) 如果time 不是LocalDateTime 对象,则会报错,然后在catch里做了兼容处理,对LocalDate 和 LocalTime 对象可以进行格式化处理,其他的直接返回异常。
方法明细-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);
方法明细-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
这个返回的数据为1
这两个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月
给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!