Java代码获取当天最晚时间写入数据库自动变为下一天的00:00:00

背景

有个需求要求将用户上传的年/月/日格式时间转为当天最晚时间23:59:59,例如上传2023/10/15,转换为2023/10/15 23:59:59,并将其存入数据库,数据库字段类型为datetime。
部分代码如下:

public static Date getEndOfDay(Date date) {
    LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
    LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
    return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant());
}

先将字符串"2023/10/15"格式的时间转为Date类型,再获取当天23:59:59。
测试时,发现数据库中数据一直显示为第二天的00:00:00,比如上述示例,显示为2023-10-16 00:00:00。

原因

在MySQL 5.6.4版本后,新增Fractional Seconds特性,参考MySQL使用手册11.2.8 Conversion Between Date and Time Types,在时间格式转换时,毫秒数在低于500时舍弃,大于等于500进位。

而在上述代码,Date精确到时分秒,看不到毫秒数,打印毫秒数可以看到

public static void main(String[] args) {
        Date now = new Date();
        Date endOfDay = getEndOfDay(now);
        System.out.println(endOfDay.getTime());
    }

在这里插入图片描述
代码获取的当天最晚时间毫秒位为999,而2023-10-15 23:59:59 对应毫秒数是1697385599000,所以落库会自动进位。

方案

若想生成的时间落库不自动进位,可以将获取的时间向前偏移,这个case偏移999,.minusMillis(999)
可以选择偏移500-999,使最终毫秒位小于500就行。
如下代码:

public static Date getEndOfDay(Date date) {
    LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
    LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
    return Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant().minusMillis(999));
}

2023.11.9 更新
感谢liu394872013大佬,可以使用truncatedTo(ChronoUnit.SECONDS); 直接精确到秒,此时毫秒位都是0,和上述解决方案得到的结果一致。
如下代码:

public static Date getEndOfDay(Date date) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(date.getTime()), ZoneId.systemDefault());
        LocalDateTime endOfDay = localDateTime.with(LocalTime.MAX);
        return Date.from(endOfDay.truncatedTo(ChronoUnit.SECONDS).atZone(ZoneId.systemDefault()).toInstant());
    }

两种写法输出结果:

1699545599000
2023-11-09 23:59:59
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值