时间类型格式化问题踩坑

记一次时间类型格式化问题:Hutools DbUtil 拼接 SQL 时如何避免日期精度丢失?

一、问题背景

在一次上游服务 SDK 开发中,我们需要通过 Hutools 工具包中的 DbUtil 实现数据持久化。在拼接 SQL 更新语句时,遇到了一个隐蔽的日期格式化问题。核心代码如下:

java 复制代码
Entity.create("table_name")
      .set("start_time", "<= " + xxx.getDate()) // 直接拼接日期对象
      .set("end_time", "IS NULL"));

其中 xxx.getDate() 对应实体类的字段定义如下:

java 复制代码
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS", timezone = "GMT+8")
private Date date; // 期望保留毫秒精度

问题现象

数据库记录中的 start_time 字段丢失了毫秒(SSS)精度,导致时间范围查询出现误差。


二、问题分析

1. 为什么会出现精度丢失?

  • 直接字符串拼接xxx.getDate() 返回 java.util.Date 对象,调用 toString() 方法时默认格式为 EEE MMM dd HH:mm:ss zzz yyyy不包含毫秒信息
  • 注解作用范围@JsonFormat 仅在 Jackson 序列化/反序列化 JSON 时生效,不影响 Date.toString() 的行为。

2. 错误示例分析

java 复制代码
// 假设 date 值为 2023-10-01 12:34:56.789
String sql = "<= " + date.toString();
// 实际拼接结果:<= Sat Oct 01 12:34:56 CST 2023

三、解决方案

1. 手动格式化日期(基础版)

通过 SimpleDateFormat 指定包含毫秒的格式:

java 复制代码
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String formattedDate = sdf.format(xxx.getDate());

Entity.create("table_name")
      .set("start_time", "<= '" + formattedDate + "'") // 注意添加引号

2. 使用 Hutools 工具类(推荐)

利用 DateUtil.format() 简化操作,避免重复造轮子:

java 复制代码
import cn.hutool.core.date.DateUtil;

String formattedDate = DateUtil.format(xxx.getDate(), "yyyy-MM-dd HH:mm:ss.SSS");

Entity.create("table_name")
      .set("start_time", "<= '" + formattedDate + "'")

四、避坑指南

1. SQL 注入风险

直接拼接字符串存在安全隐患,建议改用 预编译占位符

java 复制代码
// 使用 Hutools 的预编译方式
Entity entity = Entity.create("table_name")
                     .set("start_time", new Condition("<= ?", formattedDate));

2. 时区一致性

确保数据库连接时区与 @JsonFormatGMT+8 一致,避免时差问题。


五、总结

关键点 说明
Date.toString() 默认不包含毫秒,不可依赖其生成 SQL 字符串
@JsonFormat 局限 仅作用于 JSON 序列化,不影响其他场景的日期格式
手动格式化 使用 SimpleDateFormat 或 Hutools 工具类指定明确格式
安全拼接 优先使用预编译语句,避免拼接字符串带来的 SQL 注入风险

最佳实践

  • 始终通过 显式格式化 控制日期字符串的输出。
  • 涉及时间比较时,确保数据库字段类型与精度(如 DATETIME(3))和代码格式一致。
相关推荐
Leinwin1 小时前
OpenClaw 多 Agent 协作框架的并发限制与企业化规避方案痛点直击
java·运维·数据库
薛定谔的悦2 小时前
MQTT通信协议业务层实现的完整开发流程
java·后端·mqtt·struts
enjoy嚣士2 小时前
springboot之Exel工具类
java·spring boot·后端·easyexcel·excel工具类
罗超驿2 小时前
独立实现双向链表_LinkedList
java·数据结构·链表·linkedlist
盐水冰3 小时前
【烘焙坊项目】后端搭建(12) - 订单状态定时处理,来单提醒和顾客催单
java·后端·学习
凸头3 小时前
CompletableFuture 与 Future 对比与实战示例
java·开发语言
wuqingshun3141593 小时前
线程安全需要保证几个基本特征
java·开发语言·jvm
努力也学不会java4 小时前
【缓存算法】一篇文章带你彻底搞懂面试高频题LRU/LFU
java·数据结构·人工智能·算法·缓存·面试
攒了一袋星辰4 小时前
高并发强一致性顺序号生成系统 -- SequenceGenerator
java·数据库·mysql
小涛不学习4 小时前
Spring Boot 详解(从入门到原理)
java·spring boot·后端