1. 问题描述
本月是 2019 年的第一个月,除了迎接新年之外同样也迎来了跨年带来的关于时间参数的 bug。
废话不多说,进入正题。之前写了一个任务调度系统,支持以周为粒度进行任务的调度。针对任务的每次运行都会产生一个批次号,一般以 任务名_<年份><周数> 的格式编号(比如 job_201850
),但是在 2018 年 12 月 31 日却发现了自然周的序号发生了跳跃。
2. 分析出问题的代码
查看了一下代码,问题出在 DateTime
格式化上,原来的 DateTimeFormatter
的定义如下:
DateTimeFormatter.ofPattern("yyyyww")
预想的是 yyyy
代表年,ww
代表自然周,对于 2018 年 12 月 31 日原本预计得到的结果是 201853,但是此处 ww
得到的结果竟然是 01。
百思不得其解之下上网查了一下,发现原来错的不是 ww
,而是 yyyy
。
一般来说 yyyy
是和自然年的月份、日期搭配的,对于和自然周的搭配是要用 YYYY
的。代码如下:
public void testForWeek() {
DateTimeFormatter rightFormatter = DateTimeFormatter.ofPattern("YYYYww");
DateTimeFormatter wrongFormatter = DateTimeFormatter.ofPattern("yyyyww");
LocalDateTime now = LocalDateTime.of(2019, 1, 7, 0, 30, 0);
System.out.println(now);
String right = rightFormatter.format(now);
String wrong = wrongFormatter.format(now);
System.out.println("right = " + right);
System.out.println("wrong = " + wrong);
now = LocalDateTime.of(2018, 12, 31, 0, 30, 0);
System.out.println(now);
right = rightFormatter.format(now);
wrong = wrongFormatter.format(now);
System.out.println("right = " + right);
System.out.println("wrong = " + wrong);
}
输出结果:
2019-01-07T00:30 right = 201902 wrong = 201902 2018-12-31T00:30 right = 201901 wrong = 201801
也就是说 2018 年 12 月 31 日实际上算是 2019 年的第一周,这也算刷新了我的认知!
3. 后续订正
今天又出幺蛾子了!
今天是 2019-04-28
星期日,按理来说今天应该是 2019 年的第十七周的最后一天。可是今天用 YYYYww
格式化日期得到的却是 201918
,代码如下:
public void testForDateTimeFormatter() {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter week = DateTimeFormatter.ofPattern("YYYYww");
LocalDateTime yesterday = now.plusDays(-1);
System.out.println("yesterday = " + yesterday);
System.out.println(yesterday.getDayOfWeek().getValue());
System.out.println(week.format(yesterday));
System.out.println(this.getWeekFormat(yesterday));
System.out.println("now = " + now);
System.out.println(now.getDayOfWeek().getValue());
System.out.println(week.format(now));
System.out.println(this.getWeekFormat(now));
LocalDateTime tomorrow = now.plusDays(1);
System.out.println("tomorrow = " + tomorrow);
System.out.println(tomorrow.getDayOfWeek().getValue());
System.out.println(week.format(tomorrow));
System.out.println(this.getWeekFormat(tomorrow));
}
private String getWeekFormat(LocalDateTime localDateTime) {
int year = localDateTime.get(IsoFields.WEEK_BASED_YEAR);
int weekNum = localDateTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
return year + String.format("%02d", weekNum);
}
输出的内容为:
yesterday = 2019-04-27T10:00 6 201917 201917 now = 2019-04-28T10:00 7 201918 201917 tomorrow = 2019-04-29T10:00 1 201918 201918
也就是说按照 YYYYww
格式化的时候在星期日就会进行周号的递增!
正确格式化的的方式应该是:
private String getWeekFormat(LocalDateTime localDateTime) {
int year = localDateTime.get(IsoFields.WEEK_BASED_YEAR);
int weekNum = localDateTime.get(IsoFields.WEEK_OF_WEEK_BASED_YEAR);
return year + String.format("%02d", weekNum);
}