现象:
首先,涉及到的赋值代码片段:
Calendar calendar = Calendar.getInstance();
calendar.setTime(day);
calendar.set(Calendar.HOUR_OF_DAY,calendar.getMaximum(Calendar.HOUR_OF_DAY);
calendar.set(Calendar.MINUTE, calendar.getMaximum(Calendar.MINUTE));
calendar.set(Calendar.SECOND, calendar.getMaximum(Calendar.SECOND));
calendar.set(Calendar.MILLISECOND, calendar.getMaximum(Calendar.MILLISECOND));
return calendar.getTime();
可以看到,毫秒是取了最大的999赋值,比如就会产生一个这样的时间:
2022-01-13 23:59:59.999
特别需要注意的是,如果是通过Calendar赋值,即使没有赋值毫秒数,也会生成当前时间那一刻对应的毫秒数,所以,毫秒数就有可能是0-999之间的某一个值。
然后入库,查询可以看到日期变了
为什么会这样?我们先找下MySQL官方文档看下有没有相关解释,于是找到如下说明,5.6/5.7/8.0版本都是一样,地址:MySQL 5.6 Reference Manual
- Conversion to a
DATE
value takes fractional seconds into account and rounds the time part. For example,'1999-12-31 23:59:59.499'
becomes'1999-12-31'
, whereas'1999-12-31 23:59:59.500'
becomes'2000-01-01'
.
看到这一句就会明白,因为小数秒也就是上面的毫秒会发生四舍五入,入库才会出现上面的情况。
由于MySQL官网上最老版本的文档已经只有5.6版本的了,那么MySQL这一特性是否历来就是如此,还是后面版本改的?在网上找了下找到了之前MySQL 5.5版本的文档,地址:在线文档-mysql-5.5-en
- Conversion to a DATE value discards the time part because the DATE type contains no time information.
参照对比,可见5.5版本的是丢弃不会考虑,也不会影响,入库日期不会发生变化。
知道了是什么原因造成的,也了解到版本间的差异,接下来测试下。
MySQL 5.5 :
MySQL 5.6 :
最后,测试表明与各版本文档所述一致,自MySQL5.6以及之后版本,毫秒数会自动四舍五入,如果你的业务对于日期时间很敏感,那么就要注意了!