Spring Data JPA实体列LocalDateTime格式化微秒后三位为0问题
嘿,先看你贴出来的代码和输出,问题其实很明确:你看到的232000末尾三个0,是因为你获取的时间本身只精确到毫秒,而你的格式化模式要求显示六位微秒,没数据的部分自然就补0啦。
先复盘下你的代码和输出:
代码片段:
final String YYYY_MM_DD_HH_MM_SS_SSSSSS = "yyyy-MM-dd-HH.mm.ss.SSSSSS"; ZonedDateTime zdtAtUtc = ZonedDateTime.now(ZoneId.of("UTC")); LocalDateTime ldt = zdtAtUtc.toLocalDateTime(); DateTimeFormatter destFormatter = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS_SSSSSS); System.out.println(zdtAtUtc); System.out.println(zdtAtUtc.format(destFormatter)); System.out.println(ldt);对应的输出:
2019-07-30T15:23:18.232Z[UTC] 2019-07-30-15.23.18.232000 2019-07-30T15:23:18.232
为什么会出现末尾三个0?
你看zdtAtUtc的输出是.232Z,这说明这个时间只捕获到了毫秒级的精度(千分之一秒,三位小数),而你的格式化串SSSSSS是用来表示微秒(百万分之一秒,六位小数)的。当原时间没有微秒级的信息时,Java的DateTimeFormatter就会把空缺的三位补成0,所以就出现了232000。
另外,ZonedDateTime.now()的精度取决于你的系统时钟——很多操作系统默认的时钟精度就是毫秒级,不会提供更精细的微秒/纳秒数据。
怎么解决这个问题?
结合你提到的Spring Data JPA实体列的需求,分两步处理:
1. 确保时间源带有微秒级精度
如果是测试用,你可以手动构造一个带微秒的时间来验证格式化是否正常:
// 手动构造包含微秒的ZonedDateTime(最后一个参数是纳秒,232456000 = 232毫秒 + 456微秒) ZonedDateTime zdtWithMicros = ZonedDateTime.of(2019, 7, 30, 15, 23, 18, 232456000, ZoneId.of("UTC")); System.out.println(zdtWithMicros.format(destFormatter)); // 输出会是:2019-07-30-15.23.18.232456
如果是生产环境,需要确保你的系统时钟支持微秒级精度(部分Linux系统可以,Windows可能需要调整),或者使用专门的高精度时钟实现。
2. Spring Data JPA实体的配置
要在JPA中正确存储和读取微秒级时间,需要注意数据库字段和实体类的配置:
- 数据库端:把字段类型设置为支持微秒的类型,比如MySQL的
DATETIME(6)(括号里的6表示保留六位小数,即微秒级) - 实体类端:在字段上配置对应精度,比如用JPA注解:
import javax.persistence.Column; import java.time.LocalDateTime; // ... @Column(columnDefinition = "DATETIME(6)") // 指定数据库字段类型为带6位小数的datetime private LocalDateTime createTime;
这样当你从数据库读取时间时,LocalDateTime会保留完整的微秒信息,再用你的格式化串处理时,就不会出现末尾的000了。
小结
本质上问题不是格式化的问题,而是时间本身没有微秒数据。只要确保你的时间源(不管是生成的还是从数据库读取的)带有微秒级精度,再配合正确的格式化串和JPA配置,就能得到你想要的结果啦。
内容的提问来源于stack exchange,提问作者Nagendra Busam

