时间设置的是23点59分59秒,数据库却存的是第二天00∶00∶00
点击关注公众号,“技术干货” 及时达!问题描述昨天下班的时候,运营反馈了一个问题,明明设置的是两天后解封,为什么提示却是三天后呢。
比如今天(6.16)被拉入黑名单了,用户报名会提示 “6.19号恢复报名”,但是现在却提示6月20号才能报名,经过排查发现,就是解封的时间被多加了 1s 中,本来应该是存2025-06-18 23:59:59,但是数据库却是2025-06-19 00:00:00。
看了数据库有接近一半的数据是正确的,有一半的数据是第二天0晨(百思不得其解啊??)
「代码逻辑实现:」
LocalDateTime currentTime = LocalDateTime.now();
LocalDateTime futureTime = currentTime.plus(2, ChronoUnit.DAYS);
// 设置了为当天的最后一秒啊
LocalDateTime resultTime = futureTime.withHour(23).withMinute(59).withSecond(59);
BlackAccount entity =newBlackAccount();
// 实体字段类型为Date,数据库是timestamp
entity.setDeblockTime(Date.from(resultTime.atZone(ZoneId.systemDefault()).toInstant()));
blackAccountService.save(entity);
?看到上面的代码,有没有大佬已经发现问题了。确实上面的代码存在问题
解决过程排查思路一、排除代码问题1.确认了项目中所有设置DeblockTime的地方 只有1处。排除了代码逻辑问题,被其他代码覆盖问题;
二、问问AI:LocalDateTime futureTime = currentTime.plus(oaConfigActivityBlacklist.getBlockDay(), ChronoUnit.DAYS);
LocalDateTime resultTime = futureTime.withHour(23).withMinute(59).withSecond(59);
Date date = Date.from(resultTime.atZone(ZoneId.systemDefault()).toInstant());
这种写法能保证最后的date 的时分秒为 23时59分59秒么?
「ai的答案如下」:
1.「夏令时(DST)影响」「场景」:若时区在目标日期存在夏令时调整(如时钟回拨或前拨),可能导致时间偏差。
「示例」:
假设系统时区为Europe/Paris,2023 年 10 月 29 日凌晨 3 点时钟回拨到 2 点。若futureTime是该日,设置23:59:59后,转换为 UTC 时可能变为21:59:59Z或22:59:59Z,取决于时钟调整规则。2.「时区转换问题」「场景」:若currentTime是其他时区的时间(如 UTC),直接转换可能导致时间偏移。
「示例」:
若currentTime是 UTC 时间2023-10-01T16:00:00Z,系统时区为Asia/Shanghai(UTC+8)。添加 1 天后得到2023-10-02T16:00:00Z,设置为23:59:59后转换为Date,实际对应 UTC 时间2023-10-02T15:59:59Z。?看了数据的时间分布,任何时间点 都存在23:59:59和00:00:00的情况,就算创建时间相差几分钟的情况下,都存在这两种数据。
?三、批量插入数据测试看看能不能复现这个问题,会不会插入时候精度等其他问题:
for(inti =0; i 100; i++) {
Thread.sleep(100);
LocalDateTime currentTime = LocalDateTime.now();
LocalDateTime futureTime = currentTime.plus(2, ChronoUnit.DAYS);
// 设置了为当天的最后一秒啊 LocalDateTime resultTime = futureTime.withHour(23).withMinute(59).withSecond(59);
BlackAccount entity =newBlackAccount();
// 实体字段类型为Date,数据库是timestamp
entity.setDeblockTime(Date.from(resultTime.atZone(ZoneId.systemDefault()).toInstant()));
blackAccountService.save(entity);
}
果然还真复现了,有一半的数据是2025-06-19 23:59:59有一半的数据是2025-06-20 00:00:00
定位问题通过demo的复现,可以确认是在存数据库的时候出了问题。 因为Date的精度是控制在毫秒,pgsql 中TimeStamp 的精度用的默认值,精确到秒,所以在插入的时候Date的毫秒部分大于等于500的时候就会加1秒处理。入库之后就变成了第二天的00:00:00呢
解决方案要么将java对象的时间精度和 数据库的精度保持一致,要么就将java对象多余的精度置为0,解决方案如下:
方案1:代码中清空秒后面的数据
修改前:futureTime.withHour(23).withMinute(59).withSecond(59);
修改后: futureTime.withHour(23).withMinute(59).withSecond(59).withNano(0);方案2:调整数据库TimeStamp精度不小于java(date)对象的精度
修改前:
修改后:知识扩展1. Date 和 LocalDateTime特性java.util.Date(Java 1.0)java.time.LocalDateTime(Java 8+)「精度」毫秒级(1/1000 秒)纳秒级(1/1,000,000,000 秒)「包路径」java.util.Datejava.time.LocalDateTime「可变性」「可变」(修改会影响原对象)「不可变」(所有操作返回新对象)「时区感知」不存储时区,但内部时间戳基于 UTC「无时区」,仅表示本地日期和时间2. mysql 中的timestamp 和 datetime特性DATETIMETIMESTAMP「存储范围」1000-01-01 00:00:00到9999-12-31 23:59:591970-01-01 00:00:01UTC 到2038-01-19 03:14:07UTC「精度」5.6.4 版本后支持 fractional seconds(如DATETIME(6))最高精度微妙,设置0的话就表示精确到秒同上(如TIMESTAMP(6))「存储空间」8 字节4 字节(时间戳范围小)「时区感知」不存储时区信息,直接存储字面量「自动转换时区」:存储时转换为 UTC,读取时转换为会话时区「默认值」无默认值(除非显式设置DEFAULT)支持DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP「自动更新」不支持支持自动更新为当前时间(ON UPDATE)「3.适用场景建议」java 中尽量用LocalDateTime吧,毕竟LocalDateTime主要就是用来取代Date对象的,区别如下场景类型「java.util.Date」(旧 API)「java.time.LocalDateTime」(新 API)「简单本地时间记录」可使用,但 API 繁琐(需配合Calendar)推荐使用(无需时区,代码简洁)「带时区的时间处理」不推荐(时区处理易混淆)推荐使用ZonedDateTime或OffsetDateTime「多线程环境」不推荐(非线程安全)推荐(不可变设计,线程安全)「数据库交互(JDBC 4.2+)」需转换为java.sql.Timestamp直接支持(如pstmt.setObject(1, localDateTime))「时间计算与格式化」需依赖SimpleDateFormat(非线程安全)推荐(DateTimeFormatter线程安全)「高精度需求(纳秒级)」仅支持毫秒级支持纳秒级(1/1,000,000,000 秒数据库到底是用timestamp还是datetime呢,跨国业务用timestamp 其他场景建议用datetime:场景推荐类型原因存储历史事件时间(如订单创建时间)DATETIME不依赖时区,固定记录用户输入的时间记录服务器本地时间(如定时任务执行时间)DATETIME无需时区转换,直接反映服务器时间多时区应用(如跨国业务)TIMESTAMP自动处理时区转换,确保数据一致性(如登录时间)需要自动更新时间戳TIMESTAMP支持ON UPDATE CURRENT_TIMESTAMP特性存储范围超过 2038 年DATETIMETIMESTAMP仅支持到 【2038】 年微秒级精度需求DATETIME(6)或TIMESTAMP(6)根据是否需要时区转换选择总结本文主要讲述了在处理用户解封时间时,因 Java 代码中时间精度与数据库TIMESTAMP类型精度不一致,导致约一半数据存储时间比预期多 1 秒的问题。通过排查与测试,定位问题并给出了 Java 对象时间精度和调整数据库精度两种解决方案,同时对比了 Java 和数据库中多种时间类型的特性及适用场景 。
AI编程资讯AI Coding专区指南:https://aicoding.juejin.cn/aicoding
点击"阅读原文"了解详情~
阅读原文
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设、网站改版、域名注册、主机空间、手机网站建设、网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。 项目经理在线