日期格式‘YYYY-MM-DD’中的BUG
1. 日期格式
先来看一下日期格式主要有下面三种,US style,Euro style,RFC 3389。
Layout Format string Example
------------------------ ------------- ----------
US style (Dec 29, 2019) MM/DD/YYYY 12/29/2019
Euro style (29 Dec 2019) DD/MM/YYYY 29/12/2019
RFC 3339 (2019-12-29) YYYY-MM-DD 2019-12-29
2. 时间转换类
开发中,我们经常需要将时间进行转换成我们需要的格式,我们可以使用JDK8提供的一个DateTimeFormatter
类来完成对日期的转换,如下面的代码:
public class CarefulWithThatDateEugene {private static void tryit(int Y, int M, int D, String pat) {DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pat);LocalDate dat = LocalDate.of(Y, M, D);String str = fmt.format(dat);System.out.printf("Y=%04d M=%02d D=%02d " +"formatted with " +"\"%s\" -> %s\n", Y, M, D, pat, str);}public static void main(String[] args) {tryit(2020, 01, 20, "MM/DD/YYYY");tryit(2020, 01, 21, "DD/MM/YYYY");tryit(2020, 01, 22, "YYYY-MM-DD");}
}
上面的代码执行之后,可以完美的输出:
Y=2020 M=01 D=20 formatted with "MM/DD/YYYY" -> 01/20/2020
Y=2020 M=01 D=21 formatted with "DD/MM/YYYY" -> 21/01/2020
Y=2020 M=01 D=22 formatted with "YYYY-MM-DD" -> 2020-01-22
2.1 错误的DD
但是如果我们执行下面的代码去测试:
tryit(2020,05,17,"MM/DD/YYYY");
tryit(2020,05,18,"DD/MM/YYYY");
tryit(2020,05,19,"YYYY-MM-DD");
你会发现控制台会抛出异常
Exception in thread "main" java.time.DateTimeException: Field DayOfYear cannot be printed as the value 138 exceeds the maximum print width of 2at java.time.format.DateTimeFormatterBuilder$NumberPrinterParser.format(DateTimeFormatterBuilder.java:2548)at java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2179)at java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1746)at java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1720)at com.liuyao.time.CarefulWithThatDateEugene.tryit(CarefulWithThatDateEugene.java:15)at com.liuyao.time.CarefulWithThatDateEugene.main(CarefulWithThatDateEugene.java:26)
提示说Day的值为138,超过了日期的最大长度2,为什么日期会变成138呢,如果我们不管异常,输出的结果将会是:
Y=2020 M=05 D=17 formatted with "MM/DD/YYYY" -> 05/138/2020
Y=2020 M=05 D=18 formatted with "DD/MM/YYYY" -> 139/05/2020
Y=2020 M=05 D=19 formatted with "YYYY-MM-DD" -> 2020-05-140
可见日期都不对了,因为 DD
代表的并不是一个月的某一天,而是一年的某一天,所以才会出现138超过31的值。
所以我们应该使用 dd
来转换日期。
2.2 错误的YYYY
然后继续执行代码:
tryit(2018,12,30,"YYYY-MM-dd");
tryit(2018,12,31,"YYYY-MM-dd");
tryit(2019,01,01,"YYYY-MM-dd");
输出的结果是:
Y=2018 M=12 D=30 formatted with "YYYY-MM-dd" -> 2019-12-30
Y=2018 M=12 D=31 formatted with "YYYY-MM-dd" -> 2019-12-31
Y=2019 M=01 D=01 formatted with "YYYY-MM-dd" -> 2019-01-01
可见前面两个的2018年变成了2019年,年份变了。
这是为什么呢?因为YYYY
使用的基于周的年份,而不是基于天数的,会计人员可以使用 YYYY
来避免两年的日期分割,从而方便的计算工资等, 它的转换采用下面的规则:
- The first day of every week is Monday.(每周的第一天是星期一)
- If a week is split at the end of the year then it is assigned to the year in which more that half of the days of that week occur.(如果一个星期在年底被分割,那么它被分配到一年中超过一半的一个星期发生)
由于上面第二条的限制:
Sun 2015-12-27 -> Payroll week 52 of 2015Mon 2015-12-28 -> Payroll week 53 of 2015
Tue 2015-12-29 -> Payroll week 53 of 2015
Wed 2015-12-30 -> Payroll week 53 of 2015
Thu 2015-12-31 -> Payroll week 53 of 2015
-------------NEW YEAR---------------------
Fri 2016-01-01 -> Payroll week 53 of 2015
Sat 2016-01-02 -> Payroll week 53 of 2015
Sun 2016-01-03 -> Payroll week 53 of 2015Mon 2016-01-04 -> Payroll week 01 of 2016
2015年,第52周之后还剩下四天,因此2016年的前三天被“放到”到2015年的工资单中。
但在2025年,情况刚好相反,到2025年底只剩下三天时间,就会被“放进”到2026年的工资单年份
Sun 2025-12-28 -> Payroll week 52 of 2025 Mon 2025-12-29 -> Payroll week 01 of 2026
Tue 2025-12-30 -> Payroll week 01 of 2026
Wed 2025-12-31 -> Payroll week 01 of 2026
-------------NEW YEAR---------------------
Thu 2026-01-01 -> Payroll week 01 of 2026
Fri 2026-01-02 -> Payroll week 01 of 2026
Sat 2026-01-03 -> Payroll week 01 of 2026
Sun 2026-01-04 -> Payroll week 01 of 2026Mon 2026-01-05 -> Payroll week 02 of 2026
所以你如果采用的是 YYYY
来格式化的年份,那么你讲不可避免的会在一年的结束或者一年的开始遇到这个问题,除非某年的第一天刚好是星期一,这样ISO-8601就会把日期分割的刚刚好。
下面就是活生生的例子:
3. 正确使用
采用 DD
来格式化代码,你会很容易发现这个错误,因为一年有85%的时间都是错误的,但是你如果采用了 YYYY
这个错误的 格式来格式年份,一年中只有1%的时间是错误的,而且这个错误还不是每7年就会出现一次的。
正确的格式化ISO-8601模板为:
yyyy-MM-dd HH:mm:ss
正确的UTC的时间模板为
yyyy-MM-dd'T'HH:mm:ss.SSSXXX
4. 参考链接
- Serious Security: The decade-ending “Y2K bug” that wasn’t
- DateTimeFormatter
- 你今天因为 YYYY-MM-dd 被提 BUG 了吗
日期格式‘YYYY-MM-DD’中的BUG相关推荐
- 将字符串格式yyyy/MM/dd的字符串转为日期,格式“yyyy-MM-dd“
将字符串格式yyyy/MM/dd的字符串转为日期,格式"yyyy-MM-dd" public static String strToDateFormat(String date) ...
- 小程序ios时间格式 yyyy/MM/dd
小程序选用f2-canvas画图表, 横坐标是时间. 实际上线后,发现android上是好的,但是iphone上显示不对,后来发现是时间格式问题,ios不识别yyyy-MM-dd, 要转换成yyyy/ ...
- js获取当前时间格式YYYY/MM/DD
//获取当前时间,格式YYYY-MM-DD function getNowFormatDate() {var date = new Date();var seperator1 = "/&qu ...
- yyyy/mm/dd变成yyyy-mm-dd
当电脑的日期格式不是yyyy/mm/dd的形式的时候,假使是yyyy-mm-dd格式, 即便在程序中格式化日期格式yyyy/mm/dd,但是做成的日期却是yyyy-mm-dd. 不能只是单纯的Shor ...
- Python写,将输入的yyyy/mm/dd格式的日期显示为yyyy年mm月dd日。
7.(程序题)编程将输入的yyyy/mm/dd格式的日期显示为yyyy年mm月dd日. str = input("请输入日期:") length=len(str) if str[6 ...
- Js日期yyyy-MM-dd与yyyy/MM/dd的区别
在JavaScript中日期yyyy-MM-dd格式与yyyy/MM/dd为不同的日期表达式 console.log('2020-10-29', new Date('2020-10-29')) con ...
- 年月日格式判断-正则表达式 YYYY/MM/DD、YYYY/MM/DD| YY/MM/DD、 ^(^(\d{4}|\d{2})(\-|\/|\.)\d{1,2}\3\d{1,2}$)|(^\d{4}…
一.简单的日期判断(YYYY/MM/DD): ^\d{4}(\-|\/|\.)\d{1,2}\1\d{1,2}$ 二.演化的日期判断(YYYY/MM/DD| YY/MM/DD): ^(^(\d{4}| ...
- YYYY/MM/dd 日期format的幺蛾子
其实YYYY/MM/dd 和yyyy/MM/dd是不同的,而且YYYY/MM/dd 可能会出现年份的大bug,下面直接上代码 @org.junit.Testpublic void dateYYYY() ...
- mysql 日期格式转换mm/dd_如何将日期格式“dd/mm/yy”转换为“yy/mm/dd”以便插入mysql数据库?...
当我从格式为"dd/mm/yy"的文件中插入日期格式为"yy/mm/dd"的数据库表时,日期错误: 我得到的不是2019:04:11,而是2011:04:19. ...
- vue3时间格式转换为yyyy/mm/dd,yyyy-MM-dd,yyyy-MM-dd hh:mm:ss,hh:mm,yyyy-MM-ddThh:mm:ss+08:00
时间格式转换为yyyy/mm/dd export const dateFormat1 = (time = new Date().getTime()) => { //YYYY/MM/DDconst ...
最新文章
- ASP.NET系统 + Access数据库
- 【hihocoder】三十九周:二分.归并排序之逆序对
- 数据结构-二叉树的非递归遍历
- 【laravel】【转发】laravel 导入导出excel文档
- 牧马人鼠标g13鼠标宏_达尔优第五代牧马人EM915游戏鼠标评测
- php添加导航和删除导航,新增/修改/删除ECSHOP后台左侧导航菜单
- 级数形式套级数的敛散性判断
- Asp.Net MVC 模型(使用Entity Framework创建模型类)1
- Java面试八股文 2021年最新Java面试题及答案汇总
- TapTap推广统计逻辑
- Android局域网工具,局域网内连接Android进行调试
- 第十六届—振兴杯计算机网络管理员决赛模拟题
- Android WebView 图片加载不出来
- window java 一键启动部署 mysql,jar
- super和this
- 共享储物柜app开发方案
- 数据分析 # 深入分析近三年以来各大城市发展情况
- 对付木马:空手入白刃谁动了我的电脑系统(转)
- vim-3 粘贴命令、替换命令、替换模式和修改命令
- 各种注意事项集合(to be continued)