在进行数据查问时,控制台报了Caused by: com.mysql.cj.exceptions.WrongArgumentException: HOUR_OF_DAY: 0 -> 1
异样,查问得悉:这是因为查mysql库,转换类型为datetime
类型的字段引起的。
网上的解决方案有多种,大多数都是通过设置时区来解决的,但遗憾的是通过测试我发现即便在将数据跑在时区正确的数据库上,在执行起来我这依然出错。
最初发现我的问题呈现在夏令时上。
夏令时
记得小时候过过几个夏令时,大略的意思就是在某一天把表调快1个小时,而后再到某一天把表再调慢1个小时。这间接造成的问题的是:xxxx年xx月xx日会对应上两个工夫戳。
比方咱们假如把表调慢的那一天是2021年10月4日的12点。具体的操作是过后钟第一次通过2021年10月4日12点时,咱们把表调到2021年10月4日11点。所以在2021年10月4日11点至12点,咱们会从新过一次。
对于工夫这块,已经回达到一个工夫戳为负的问题,也有那么点意思:https://segmentfault.com/q/1010000038248983,赶趣味的能够看看。
那么问题来了,比咱们记录用户的出世工夫,准确到分钟。如果这个人录入的是2021年10月4日11点20分,那咱们的零碎没有方法来精确的判断这个工夫是第一个11点20分,还是过1小时后的第二个11点20分。
夏令时,还给咱们带来的另一个问题。有些工夫是对应不上工夫戳的。
再比方咱们设置在2021年5月1日0时,将表调快1时,则在历史上不会呈现2021年5月1日0时至1时的工夫,所以如果咱们统计出世工夫点,用户写的是:2021年5月1日0时30分,则该数据必须是个假数据。
排查
夏令时讲完后,咱们讲下排查过程。其实并不是所有的数据在查问时,都会报这种异样,所以要把那个非凡的点找进去,这里给一种最笨的展现办法:
boolean last = false; int page = 0; Pageable pageable = PageRequest.of(page, 1); while (!last) { try { Page<Resident> residents = this.residentRepository.findAll(specification, pageable); page++; pageable = PageRequest.of(page, 1); last = residents.isLast(); } catch (Exception e) { last = true; e.printStackTrace(); this.logger.info("当前页" + pageable.getPageNumber()); } }
最终控制台打印信息:2021-11-04 13:25:38.562 INFO 4226 --- [nio-8081-exec-7] c.y.s.service.ResidentServiceImpl : 当前页1089
而后咱们去数据表中把这条记录查出来:
select * FROM resident limit 1089, 1
咱们发现此人的出生日期是1947年4月15日0时0分0分。其实这个日期用户仅仅是输出了1947-4-15,只是咱们存的时候主动增加了0时0分0秒。但凑巧,这个数字对应的工夫戳,它恰好就是一个有效数字。
测试代码如下:
@Test void time() { Calendar calendar = Calendar.getInstance(); // 启用严格查看模式 calendar.setLenient(false); calendar.set(1947, 3, 15, 0, 0, 0); System.out.println(calendar.getTime()); }
异样内容:java.lang.IllegalArgumentException: HOUR_OF_DAY: 0 -> 1
它是在说:你说本人是0点出世的,然而本JAVA大牛查了一下,1947年4月15日就没有0点,当天的最小值是1点。
解决问题
问题找到了,解决便是最简略的一环。
- 找到报错的历史数据,将0点改成8点。
- 找到历史的代码,将0点改成8点。
public static Timestamp getTimeStampFormIdNumber(String idNumber) { // 进行出生日期赋值 int year = Integer.valueOf(idNumber.substring(6, 10)); int month = Integer.valueOf(idNumber.substring(10, 12)); int day = Integer.valueOf(idNumber.substring(12, 14)); Calendar calendar = Calendar.getInstance();- calendar.set(year, month - 1, day, 0, 0, 0);+ calendar.set(year, month - 1, day, 12, 0, 0); return new Timestamp(calendar.getTimeInMillis()); }
至于为什么改成12点,是因为我发现夏令时的批改(调快或调慢)都躲避了12点,所以工夫为12点,则能够无效防止有效工夫戳的问题.当然了,你还能够改成13点,只有不是凌晨的那几个小时,都没有什么问题。