关于LocalDateTime解析的三种模式

Java8引入了新的时间格式Api:LocalDateTimeLocalDateLocalTime,分别用于处理日期-时间、日期和时间。使用他们,我门可以很方便的把日期转成String或者把String解析成日期。下面我们深入探究一下对于StringLocalDateTime,java提供的三种模式。
以下以LocalDateTime为例:
对于String转日期,平时用的最多的就是LocalDateTimeparse方法。

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

public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
	Objects.requireNonNull(formatter, "formatter");
	return formatter.parse(text, LocalDateTime::from);
}
复制代码

parse方法提供两个重载方法,其实最后调用的都是parse(CharSequence text, DateTimeFormatter formatter),这里的关键就是DateTimeFormatter,当我们只传text的时候,默认的解析规则是:DateTimeFormatter.ISO_LOCAL_DATE_TIME,他的格式如下所示:

/**
     * The ISO date-time formatter that formats or parses a date-time without
     * an offset, such as '2011-12-03T10:15:30'.
     * The returned formatter has a chronology of ISO set to ensure dates in
     * other calendar systems are correctly converted.
     * It has no override zone and uses the {@link ResolverStyle#STRICT STRICT} resolver style.
     */   
public static final DateTimeFormatter ISO_LOCAL_DATE_TIME;
    static {
        ISO_LOCAL_DATE_TIME = new DateTimeFormatterBuilder()
                .parseCaseInsensitive()
                .append(ISO_LOCAL_DATE)
                .appendLiteral('T')
                .append(ISO_LOCAL_TIME)
                .toFormatter(ResolverStyle.STRICT, IsoChronology.INSTANCE);
    }
复制代码

也就是yyyy-MM-ddTHH:mm:ss(这里有个关键点就是方法最后有个参数ResolverStyle.STRICT,这就是严格模式)。这种数据格式是ECMAScript基于ISO 8601扩展格式的简化,在国外比较常见。我们平时使用最多的是yyyy-MM-dd HH:mm:ss这个格式,比较方便前端展示。如果要转换成这种格式,那应该怎么办呢?
我们可以自定义一个DateTimeFormatter来完成。

LocalDateTime parse = LocalDateTime.parse( "2021-02-23 08:02:02", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//输出结果
2021-02-23T08:02:02

LocalDateTime parse = LocalDateTime.parse( "2021-02-29 08:02:02", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
//输出结果
2021-02-28T08:02:02
        
复制代码

细心的朋友可能已经发现了,我传的是02-29,为什么结果是02-28呢,这里就牵扯本文所说的解析模式了。首先我们看一下DateTimeFormatter.ofPattern的源码:

public static DateTimeFormatter ofPattern(String pattern) {
	return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
}

public DateTimeFormatter toFormatter() {
	return toFormatter(Locale.getDefault(Locale.Category.FORMAT));
}

public DateTimeFormatter toFormatter(Locale locale) {
	return toFormatter(locale, ResolverStyle.SMART, null);
}

复制代码

关键的地方就是 toFormatter,依次进入方法可以看到最后传入了一个默认参数:ResolverStyle.SMART,顾名思义,smart就是智能模式,ResolverStyle提供:STRICT(严格),SMART(智能),LENIENT(宽松)三种模式对日期进行解析,下面我们详细讨论下三种模式的不同。

严格模式

我们首先定义一个严格的日期解析规则,然后用它解析日期。

    /**
     * 自定义严格日期格式:yyyy-MM-dd HH:mm:ss
     **/
    public static DateTimeFormatter STRICT_DATE_TIME = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(ISO_LOCAL_DATE)
            .appendLiteral(" ")
            .append(ISO_LOCAL_TIME)
            .toFormatter(Locale.CHINESE)
            .withResolverStyle(ResolverStyle.STRICT);

LocalDateTime normal = LocalDateTime.parse( "2021-04-30 08:02:02", STRICT_DATE_TIME);
// 输出结果
2021-04-30T08:02:02
LocalDateTime normal = LocalDateTime.parse( "2021-04-31 08:02:02", STRICT_DATE_TIME);
// 输出结果
Caused by: java.time.DateTimeException: Invalid date 'APRIL 31'
复制代码

由上面代码可以得知:对于不合法的日期,严格模式直接抛出异常。大家也可以改变一下其他字段,最后会发现,必须严格按照时间日期的取值,否则转换都会抛出异常。

智能模式

    /**
     * 自定义智能日期格式:yyyy-MM-dd HH:mm:ss
     **/
    public static DateTimeFormatter SMART_DATE_TIME = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(ISO_LOCAL_DATE)
            .appendLiteral(" ")
            .append(ISO_LOCAL_TIME)
            .toFormatter(Locale.CHINESE);//默认智能模式

    LocalDateTime normal = LocalDateTime.parse( "2021-02-29 18:02:02", SMART_DATE_TIME);
	//输出结果
	2021-02-28T18:02:02
    LocalDateTime unnormal = LocalDateTime.parse( "2021-04-31 08:02:02", SMART_DATE_TIME);
	//输出结果
	2021-04-30T08:02:02
复制代码

对于不合法的日期,智能模式会自动把数据转换成最近的有效日期,但是要注意不合法日期也是有规则的,超出个字段的取值范围也会有问题。你搞个”2021-02-32″这个格式还是会抛出异常DateTimeException

宽松模式

    public static DateTimeFormatter LENIENT_DATE_TIME = new DateTimeFormatterBuilder()
            .parseCaseInsensitive()
            .append(ISO_LOCAL_DATE)
            .appendLiteral(" ")
            .append(ISO_LOCAL_TIME)
            .toFormatter(Locale.CHINESE)
            .withResolverStyle(ResolverStyle.LENIENT);

	LocalDateTime normal = LocalDateTime.parse( "2021-02-32 18:02:02", LENIENT_DATE_TIME);
	//输出结果
	2021-03-04T18:02:02
    LocalDateTime unnormal = LocalDateTime.parse( "2021-13-31 08:02:02", LENIENT_DATE_TIME);
	//输出结果
	2022-01-31T08:02:02
复制代码

宽松模式对数据的要求就比较宽松了,只要是数字一般都会解析成功,他会自动把不合法的日期转为有效日期,比如说,13就会转成12+1,这样2021年就变成了了2022年,天和时分秒同理。

综上所述,我们可以总结出:

STRICT 对于时间格式要求最严格,强制合法时间才能解析
SMART 对于有效期内的日期字段,可以解析为最近的有效日期,常用与处理闰年2月份,和跨月时间格式问题
LENIENT 对于时间格式要求最宽松,只要是数字就能解析,而且会自动转换为有效日期,但是转换后的日期与之前相差较大,慎用!!!
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享