• 日期格式化跨年bug,是否与你不期而遇?


    2020年来临之前,日期格式化操作也为程序员准备了一个跨年级别的bug,不知你的系统是否遇到?

    临近2020年元旦的几天,不少网站出现了类似2020/12/29,2020/12/30,2020/12/31这样的日期显示。神奇不?就连微信的提供的订阅号助手工具都出现了这样的错误。

    下面两张图是本公众号“程序新视界”在12月31日订阅号助手助手中的截图。

    新增粉丝时间显示的部分内容。

    image

    评论区的时间显示的部分内容。
    image

    上图中,新增粉丝显示的时间和评论的时间均为“2020/12/31”。那么,下面我们就来分析一下出现此bug的原因。实例胜千言,先用示例还原一下此bug。

    示例一,还原示例:

    public class DateFormatBug {
    
    	public static void main(String[] args) throws ParseException {
    		// 示例一
    		printBugDate();
    	}
    
    	private static void printBugDate() throws ParseException {
    		SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
    		Date date = sdf.parse("2020-1-1 13:12:12");
    		System.out.println(date);
    		String dateStr = sdf.format(date);
    		System.out.println(dateStr);
    	}
    }
    

    猜猜第一行和第二行打印的结果分别是什么?如果猜对一个说明很聪明,因为上面已经说了,此实例为还原bug。

    打印日志为:

    Sun Dec 29 13:12:12 CST 2019
    2020-12-29 13:12:12
    

    神奇不?把字符串“2020-1-1 13:12:12”解析成日期打印出来竟然成2019年12月29日了!!!然后再对日期进行处理竟然变成2020-12-29日了!彻底乱套了,我们想要的是2020-1-1的日期啊。

    示例二,延伸示例:

    private static void printBugDateExtend() throws ParseException {
    	SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");
    	Date date = sdf.parse("2019-12-31 13:12:12");
    	System.out.println(date);
    	String dateStr = sdf.format(date);
    	System.out.println(dateStr);
    }
    

    这次只是把日期从2020-1-1改为2019-12-31,猜猜打印结果是什么?保证你猜不到。下面是打印结果:

    Sun Dec 30 13:12:12 CST 2018
    2019-12-30 13:12:12
    

    2018年12月30?这次连年份都错了。

    好了,不卖关子了,如果你的IDE上安装的有阿里巴巴操作规范手册的插件。你会发现“YYYY-MM-dd HH:mm:ss”上面已经有提示信息了。同样,如果你打开新版(华山版)阿里巴巴Java开发手册,对此问题已经进行了明确的说明了。

    image

    那么,哪里可以获得新版的《阿里巴巴Java开发手册》?关注公众号“程序新视界”的朋友,只需回复“005”即可获得PDF版本。新的一年,没事看看大厂的开发手册,借鉴一下经验,避免踩坑也是不错的。当然,关注公众号持续学习也是另外一种不错的选择。

    同时,也可参看javadoc中对week-based-year的说明,相关链接如下:https://docs.oracle.com/javase/8/docs/api/java/time/temporal/WeekFields.html

    A week is defined by:
    
    (1) The first day-of-week. For example, the ISO-8601 standard considers Monday to be the first day-of-week.
    
    (2) The minimal number of days in the first week. For example, the ISO-8601 standard counts the first week as needing at least 4 days.
    
    Together these two values allow a year or month to be divided into weeks.
    

    总结一下就是:在基于周的年份中,每周仅属于某一年。一年中的第1周要求从一周的第一天开始,并且天数要大于4天(the minimum number of days),所以跨年周具体是哪一年还得看具体情况。

    不过无论怎样,最好的方法就是避免使用大写的“Y”来代表年份。

    尽信书不如无书,我们将代码中“Y”修改为“y”,再执行一遍看看效果。

    private static void printDate() throws ParseException {
    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	Date date = sdf.parse("2020-1-1 13:12:12");
    	System.out.println(date);
    	String dateStr = sdf.format(date);
    	System.out.println(dateStr);
    }
    
    private static void printDateExtend() throws ParseException {
    	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    	Date date = sdf.parse("2019-12-31 13:12:12");
    	System.out.println(date);
    	String dateStr = sdf.format(date);
    	System.out.println(dateStr);
    }
    

    打印结果显示如下:

    Wed Jan 01 13:12:12 CST 2020
    2020-01-01 13:12:12
    Tue Dec 31 13:12:12 CST 2019
    2019-12-31 13:12:12
    

    很显然,这个跨年bug被修复了。

    经过这个问题,我们是否会思考一个问题:高手与新手的差不在哪里?或许上面的问题就能够回答,同样是日期格式化,在正常情况下两种写法都可正常运行,无法区分高手与新手。而只有在某时某刻某些极端情况下才能看出高手之高。

    那么高手是从哪里来的?是从坑中跳出来的。或许他比你早掉进去早出来了,或许他博览群书有那么一次“不期而遇”,也或许就是像你现在一样看到这篇文章。

    原文链接:《跨年bug,是否与你不期而遇?


    程序新视界:精彩和成长都不容错过
    ![程序新视界-微信公众号](https://img2018.cnblogs.com/blog/1742867/201910/1742867-20191013111755842-2090947098.png)
  • 相关阅读:
    Python自动化运维之28、Django(二)
    Python自动化运维之27、Django(一)
    Python自动化运维之26、Web框架本质、MVC与MTV
    Python自动化运维之25、Ajax
    高级接口--高级群发接口
    高级接口--用户标签管理
    高级接口--获取用户基本信息
    高级接口--获取用户地理位置
    高级接口--生成带参数二维码
    高级接口--OAuth2.0网页授权
  • 原文地址:https://www.cnblogs.com/secbro/p/12131361.html
Copyright © 2020-2023  润新知