Invalid format: "07-31-2017 7:32:06 PM" is malformed at "PM" 异常源码分析

1 测试代码如下:

import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public static void main(String[] args) {
        String date = "07-31-2017 7:32:06 PM";
        DateTimeFormatter builder = DateTimeFormat.forPattern("MM-dd-yyyy h:mm:ss a");
        System.out.println(builder.parseDateTime(date));
    }

运行,抛出如下异常:

Exception in thread "main" java.lang.IllegalArgumentException: Invalid format: "07-31-2017 7:32:06 PM" is malformed at "PM"
    at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:945)
    at com.cardniu.loanremind.push.Entry.main(Entry.java:31)

2 尝试解决
参考这篇文章,https://stackoverflow.com/questions/32045626/joda-hhmm-am-is-malformed-at-am/,改成如下代码:

public static void main(String[] args) {
        String date = "07-31-2017 7:32:06 PM";
        //withLocale(Locale.ENGLISH)是新增代码
        DateTimeFormatter builder = DateTimeFormat.forPattern("MM-dd-yyyy h:mm:ss a").withLocale(Locale.ENGLISH);
        System.out.println(builder.parseDateTime(date));
    }

问题解决,但是很可惜,这篇文章只给出了解决方案,但没有解释原因,于是我就调试源代码,来找到背后的原因.

3 源码调试.
根据抛出的异常,我们首先查看DateTimeFormatter类的parseDateTime方法源码,如下:
这里写图片描述
首先简单解释下1出代码,创建一个DateTimeParserBucket对象,代码如下:
这里写图片描述
请特别留意?号出的代码,在后面揭秘原因时,要用到
关于DateTimeParserBocket类的解释,如下:
这里写图片描述
简单分析,会发现是由于newPos的值为负数时,导致程序有异常的,于是我们接着查看org.joda.time.format.DateTimeFormatterBuilder.Composite.parseInto方法的源码:
这里写图片描述
1处的DateTimeParserBucket类不再啰嗦,关于InternalParser接口的parseInto方法解释如下:
这里写图片描述
对3处的代码理解:就是利用各种InternalParser的实现类对”07-31-2017 7:32:06 PM”的每部分(年,月,日,时,分,秒)进行解析,保存到bucket中,那InternalParser的实现类又有那些了?如下图:
这里写图片描述
其中2处的org.joda.time.format.DateTimeFormatterBuilder.Composite这种解析实现类我们在前面使用过,因为我们的异常出现在对”PM”的解析上,而对”PM”使用的解析实现类为1处的org.joda.time.format.DateTimeFormatterBuilder.TextField实现类,来让我们分析下该解析类的parseInto方法:
这里写图片描述
1处代码:从bucket中获得保存的Locale(想起来在前面提到的?处的代码了吗).
2处代码:根据不同的Locale往validValues中put诸如(“上午”,true),(“下午”,true)这类键值对(当Locale为CHINESE时),若Locale.ENGLISH,put诸如(“am”,true),(“AM”,true),(“pm”,true),(“PM”,true)等值.
3处代码是关键,请看下图:
这里写图片描述
此时真相大白于天下, validValues不存在key为”PM”的值,导致程序返回异常,
原因在于创建bucket对象时使用的是Locale.CHINESE(此时的Locale.getDefault()返回值).validValues中put诸如(“上午”,true),(“下午”,true)这类键值对
原因找到了,修改起来就很容易,那就是在创建DateTimeFormatter对象实例时指定Locale为ENGLISH.

总结

  • 1通过以上分析,我们可以明白解析”07-31-2017 7:32:06 pM”中的”pM”是肯定不成功的,就算你设置Locale为ENGLISH,也不行,因为不支持这种key值.

  • 2 这是自己第一次通过分析源码来找到异常背后的原因,而不只是停留在把问题解决就够了的层面,做到知其然更要知其所以然.

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值