高级JAVA开发必备技能:java8 新日期时间API((三)JSR-310:格式化和解析)(JAVA 小虚竹

学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、全套PDF电子书

书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。

四、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

五、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

    public String format(TemporalAccessor temporal) {
        StringBuilder buf = new StringBuilder(32);
        formatTo(temporal, buf);
        return buf.toString();
    }



首先new了个StringBuilder对象,用来拼接字符串;

然后调用**formatTo(temporal, buf)**方法

public void formatTo(TemporalAccessor temporal, Appendable appendable) {
    Objects.requireNonNull(temporal, "temporal");
    Objects.requireNonNull(appendable, "appendable");
    try {
        DateTimePrintContext context = new DateTimePrintContext(temporal, this);
        if (appendable instanceof StringBuilder) {
            printerParser.format(context, (StringBuilder) appendable);
        } else {
            // buffer output to avoid writing to appendable in case of error
            StringBuilder buf = new StringBuilder(32);
            printerParser.format(context, buf);
            appendable.append(buf);
        }
    } catch (IOException ex) {
        throw new DateTimeException(ex.getMessage(), ex);
    }
}

**formatTo(temporal, buf)**方法也是先判断两个入参空处理。

然后,Instant对象被封装在一个新new的DateTimePrintContext对象

运行demo有问题,进行排查

		//根据特定格式格式化日期
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String dateStr = DateUtil.format(new Date(),dtf);
		System.out.println(dateStr);

image-20210725195348793

到这里已经是jdk的源码了DateTimeFormatter.format

image-20210725195424950

image-20210725195522610

image-20210725195636339

从上面可知,会调用 NumberPrinterParser.format() NumberPrinterParser是在DateTimeFormatterBuilder类中的。

image-20210725195947802

到这一步会报错

image-20210725200153850

为什么会报错呢,我们来看下context.getValue(field)发生了什么:

image-20210725200349650

从上面代码可行,temporal实际上是Instant对象,Instant.getLong只支持四种字段类型。。

NANO_OF_SECOND
MICRO_OF_SECOND
MILLI_OF_SECOND
INSTANT_SECONDS

image-20210725200551164

如果不是上面这几种字段类型,则抛出异常

DateUtil.format当遇到DateTimeFormatter会将Date对象首先转换为Instant,因为缺少时区,导致报错。

解决方案:
/\*\*
 \* 根据特定格式格式化日期
 \*
 \* @param date 被格式化的日期
 \* @param format
 \* @return 格式化后的字符串
 \* @since 5.0.0
 \*/
public static String format(Date date, DateTimeFormatter format) {
   if (null == format || null == date) {
      return null;
   }
   Instant instant = date.toInstant();
   ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
   LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
   return format.format(localDateTime);
}

先把date类型转化为LocalDateTime类型,然后再进行DateTimeFormatter.format(LocalDateTime)的格式化

测试demo

//根据特定格式格式化日期
String str = "2021-07-25 20:11:25";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd");
Date date = DateUtil.parse(str);
String dateStr = DateUtil.format(date,dtf);
System.out.println(dateStr);
Assert.assertEquals(str, dateStr);

image-20210725201444728

DateTimeFormatterBuilder

DateTimeFormatterBuilder类说明

DateTimeFormatter 的所有格式化器都是用DateTimeFormatterBuilder 建造器类创建的。

看下面两个ofPattern 源码:

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

解析风格配置

官方提供了四种解析风格的配置,如下枚举 SettingsParser

 static enum SettingsParser implements DateTimePrinterParser {
     // 大小写敏感
        SENSITIVE,
     // 大小写不敏感
        INSENSITIVE,
     //严格
        STRICT,
     //宽松
        LENIENT;
        ...
        }

对应DateTimeFormatterBuilder 类中的方法:

// 大小写敏感
public DateTimeFormatterBuilder parseCaseSensitive()
// 大小写不敏感
public DateTimeFormatterBuilder parseCaseInsensitive()
// 严格
public DateTimeFormatterBuilder parseStrict()
// 宽松
public DateTimeFormatterBuilder parseLenient()

这四个方法对应的源码如下:

// 大小写敏感
public DateTimeFormatterBuilder parseCaseSensitive() {
        appendInternal(SettingsParser.SENSITIVE);
        return this;
    }
// 大小写不敏感
 public DateTimeFormatterBuilder parseCaseInsensitive() {
        appendInternal(SettingsParser.INSENSITIVE);
        return this;
    }
// 严格
 public DateTimeFormatterBuilder parseStrict() {
        appendInternal(SettingsParser.STRICT);
        return this;
    }
// 宽松
public DateTimeFormatterBuilder parseLenient() {
        appendInternal(SettingsParser.LENIENT);
        return this;
    }

可以看出,都是调用appendInternal 方法。

接着往下看 appendInternal 源码:

 private int appendInternal(DateTimePrinterParser pp) {
        Objects.requireNonNull(pp, "pp");
        if (active.padNextWidth > 0) {
            if (pp != null) {
                pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
            }
            active.padNextWidth = 0;
            active.padNextChar = 0;
        }
        active.printerParsers.add(pp);
        active.valueParserIndex = -1;
        return active.printerParsers.size() - 1;
    }

其中active 是一个DateTimeFormatterBuilder 实例,且这个DateTimeFormatterBuilder 实例内部有一个列表 List< DateTimePrinterParser > ,看了源码可知,真正做解析工作的是DateTimePrinterParser 对应的实例来做的。

DateTimePrinterParser 的源码:

 interface DateTimePrinterParser {

        boolean format(DateTimePrintContext context, StringBuilder buf);

        int parse(DateTimeParseContext context, CharSequence text, int position);
    }

源码有一共有16个DateTimePrinterParser 的实例。

//1.Composite printer and parser.
static final class CompositePrinterParser implements DateTimePrinterParser {...}

//2.Pads the output to a fixed width.
static final class PadPrinterParserDecorator implements DateTimePrinterParser {...}

//3.Enumeration to apply simple parse settings.
static enum SettingsParser implements DateTimePrinterParser{...}

//4. Defaults a value into the parse if not currently present.
static class DefaultValueParser implements DateTimePrinterParser {...}

//5.Prints or parses a character literal.
static final class CharLiteralPrinterParser implements DateTimePrinterParser {...}

//6.Prints or parses a string literal.
static final class StringLiteralPrinterParser implements DateTimePrinterParser {...}

//7.Prints and parses a numeric date-time field with optional padding.
static class NumberPrinterParser implements DateTimePrinterParser {...}

//8.Prints and parses a numeric date-time field with optional padding.
static final class FractionPrinterParser implements DateTimePrinterParser {...}

//9.Prints or parses field text.
static final class TextPrinterParser implements DateTimePrinterParser  {...}

//10.Prints or parses an ISO-8601 instant.
static final class InstantPrinterParser implements DateTimePrinterParser  {...}

//11.Prints or parses an offset ID.
static final class OffsetIdPrinterParser implements DateTimePrinterParser   {...}

//12.Prints or parses an offset ID.
static final class LocalizedOffsetIdPrinterParser implements DateTimePrinterParser {...}

//13.Prints or parses a zone ID.
static class ZoneIdPrinterParser implements DateTimePrinterParser {...}

//14. Prints or parses a chronology.
 static final class ChronoPrinterParser implements DateTimePrinterParser {...}

//15.Prints or parses a localized pattern.
static final class LocalizedPrinterParser implements DateTimePrinterParser {...}

//16.Prints or parses a localized pattern from a localized field.
 static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {...}

推荐相关文章

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的时区规则

文末有福利领取哦~

👉一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。img

👉二、Python必备开发工具

img
👉三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
img

👉 四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。(文末领读者福利)
img

👉五、Python练习题

检查学习结果。
img

👉六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
img

img

👉因篇幅有限,仅展示部分资料,这份完整版的Python全套学习资料已经上传

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值