跨年过程中因日期格式化引发的生产故障:格式化方式YYYYMMdd和yyyyMMdd的区别

导读:本篇文章讲解 跨年过程中因日期格式化引发的生产故障:格式化方式YYYYMMdd和yyyyMMdd的区别,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

故障背景

某公司进行一年一度的跨年上线工作,在2018年的12月30号上午忽然接到保障业务无法运行,而且影响全国业务。

故障分析

第一步:因为近期没有业务上线活动,首先排除因上线因此引起的故障
第二步:分析业务日志。发现业务中报错的原因是没有查到业务表中前期存的业务数据
第三步:查询前期存表操作,查找是什么原因导致业务数据没有存到数据库中。然后发现业务中并没有抛出任何存表异常(这是一个坑,笔者也跳进去了饶了好几次才发现)。此处解释一下:因为业务数据量比较大,因此业务上采取的是分年月的分表规则进行业务信息存储,同时此时属于跨年的时间节点,业务上一般会提前一周将下一年的表结构刷入数据库中。
第四步:故障定位。上面的数据库确实没报错,然后通过显示mybatis中sql语句方式,看到sql入的表是T_BUSI_201912的表,也就是说本来如表应该是T_BUSI_201812的表现在存到表T_BUSI_201912,很明显,这里的分表日期计算错了。因为T_BUSI_201912表结果已经提前刷入生产环境,因此没有出现入库异常。

故障重现

根据上面的分析,我们找到了错误的原因开发者使用的是YYYYMMdd格式化当前日期。那现在就用测试代码重现一下当时的故障。测试代码如下所示:

    /**
     * 故障重现
     */
    public static void  troubleReproduce() throws ParseException {
        //业务中使用的日期格式化方式
        String formate1 = "YYYYMMdd";
        //比较格式化方式
        String formate2 = "yyyyMMdd";
        //这个是故障发生的时间
        String dateTime = "20181230";
        //这个是故障发生前一天的时间
        String dateTimeTest = "20181229";
        //这个是将字符串转换成时间
        Date date = new SimpleDateFormat(formate2).parse(dateTime);
        Date dateTest = new SimpleDateFormat(formate2).parse(dateTimeTest);

        System.out.println("使用[" + formate1 + "]格式化前后{"+dateTime+"} -> " + (new SimpleDateFormat(formate1).format(date)));
        System.out.println("使用[" + formate2 + "]格式化前后{"+dateTime+"} -> " + (new SimpleDateFormat(formate2).format(date)));
        System.out.println("-----------------分割线---------------------");
        System.out.println("使用[" + formate1 + "]格式化前后{"+dateTimeTest+"} -> " + (new SimpleDateFormat(formate1).format(dateTest)));
        System.out.println("使用[" + formate2 + "]格式化前后{"+dateTimeTest+"} -> " + (new SimpleDateFormat(formate2).format(dateTest)));
    }

打印结果如下:

使用[YYYYMMdd]格式化前后{20181230} -> 20191230
使用[yyyyMMdd]格式化前后{20181230} -> 20181230
-----------------分割线---------------------
使用[YYYYMMdd]格式化前后{20181229} -> 20181229
使用[yyyyMMdd]格式化前后{20181229} -> 20181229

这个例子就重现了案发现场,如果是2018年12月29号的时候系统都能正常运行,到了2018年12月30号的时候系统就无法正常运行了,应该存T_BUSI_201812表的数据错误的存入T_BUSI_201912中。

解释总结

上面成功找到了问题的原因,那我们要刨根问题为什么YYYYMMdd和yyyyMMdd得到的结果是不一样的,为什么YYYYMMdd出现的结果是不对的?
因为YYYY是week-based-year,表示当天所在的周属于的年份,2018年的12月30号是周日,周日在西方人认为是一周的第一天,因此本周存在跨年(2019年),所以就算入下一个年份中了。 但是2018年12月29号是本周的最后一天,这一周都在2018年,因此显示是正常的。
所以这一点程序员要谨记,尽量不要使用YYYY这样的年份规则。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/72731.html

(0)
小半的头像小半

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!