首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

一次 SimpleDateFormat 引发的惨案(1)

一次 SimpleDateFormat 引发的惨案(1)

引子

最近手头上的项目上了一个新功能,每天早上一到公司,就兴致勃勃地登上服务器去查看日志,“窥视”一下跑的正不正常。今天终于碰到“彩蛋”了:

    Invalid Date in Date Math String:'2187-02-31T16:00:00Z'
    ...
    Invalid Date in Date Math String:'0001-09-31T16:00:00Z'
    复制代码

这是什么鬼?怎么会有这样的日期?一会穿越到一百年后,一会穿越到原始社会,我想问那时的2月和9月都有31号了么?
场景

冷静~ 我们先来理一理业务场景:我这边调用S团队的服务,接口参数传了String类型的开始日期和结束日期,格式:yyyy-MM-dd。既然报了“Invalid Date ...”错误,那是不是服务方对它们进行解析时出了问题呢?登上对方的服务器看日志去,发现很多 NumberFormatException:

    2019-01-10 00:31:22 380 [com.xxx.xxx.xxx.xxx.util.DataTool]-[WARN] 2019-01-09 00:00:00 parse err
    java.lang.NumberFormatException: For input string: ".109E2.109E2"
            at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
            at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
            at java.lang.Double.parseDouble(Double.java:538)
            at java.text.DigitList.getDouble(DigitList.java:169)
            at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
            at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
            at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
            at java.text.DateFormat.parse(DateFormat.java:364)
            at com.xxx.xxx.xxx.xxx.util.DataTool.CCTToUTC(DataTool.java:29)
     
     
    2019-01-10 00:31:22 415 [com.xxx.xxx.xxx.xxx.util.DataTool]-[WARN] 2019-01-10 00:00:00 parse err
    java.lang.NumberFormatException: For input string: ""
            at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
            at java.lang.Long.parseLong(Long.java:601)
            at java.lang.Long.parseLong(Long.java:631)
            at java.text.DigitList.getLong(DigitList.java:195)
            at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
            at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
            at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
            at java.text.DateFormat.parse(DateFormat.java:364)
            at com.xxx.xxx.xxx.xxx.util.DataTool.CCTToUTC(DataTool.java:29)
    复制代码

嗯,"2019-01-09 00:00:00" 和 “2019-01-10 00:00:00” 是我传过来的参数值,对应开始日期和结束日期。这应该没什么问题。那检查一下 DataTool.java 类 CCTToUTC 这个方法的第29行:

    public class DataTool {
        
        private static Logger logger = Logger.getLogger(DataTool.class);
        
        private static SimpleDateFormat dateSdf = new SimpleDateFormat("yyyy-MM-dd");
        
        private static SimpleDateFormat timezoneSdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        
        public static String CCTToUTC(String timeString) {
            try {
                Date date = dateSdf.parse(timeString); // 第29行
                Calendar calendar = Calendar.getInstance();
                Date tgtDate = new Date(date.getTime() - calendar.getTimeZone().getRawOffset());
                return timezoneSdf.format(tgtDate);
            } catch (Exception e) {
                logger.warn(timeString+" parse err", e);
                return timezoneSdf.format(new Date());
            }
        }
    }
    复制代码

代码很简单,定义全局变量 SimpleDateFormat,在 CCTToUTC(String timeString) 中用它对传入的日期进行解析和格式化。但在第一行 parse 的时候就报错了并被捕获到,而后打印了一行 warn 日志,并返回了当前时间 format 后的时间字符串。这不是我们想要的结果。

我怀疑是不是我传入的时间有问题,于是在本类写了个 main 方法,简单 sout 打印调用该方法后的结果,尝试了几个不同的时间串,发现始终得不到上面那些令我“穿越”的日期。
返回列表