在进行数据查问时,控制台报了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点。

解决问题

问题找到了,解决便是最简略的一环。

  1. 找到报错的历史数据,将0点改成8点。
  2. 找到历史的代码,将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点,只有不是凌晨的那几个小时,都没有什么问题。