问题全景回顾
初始疑惑
由于我们项目中引入了es组件,针对es中存储了很多关于日期的问题,由于我们项目需要实现国际化所以肯定需要考虑时区问题,所以es中日期相关的字段都采用了时间戳,那如何优雅的将业务中不同类型的日期值在写入到es中转换成时间戳的问题进行了延伸,包括前期一篇博客也发布了关于时区问题的处理跨时区国际化解决方案
result.setClientTime(data.getClientTime()); // 直接传递Date对象
@Field(type = FieldType.Date, format = DateFormat.epoch_millis) // 却声明需要毫秒时间戳格式
private Date clientTime;
给出的代码是Java语言,涉及到一个类的字段定义和设置方法。具体来说,用户有一个result对象,调用了setClientTime方法,传入的参数是data.getClientTime() 。然后,用户定义了一个clientTime字段,使用了@Field注解,指定了类型为FieldType.Date,格式为epoch_millis,即毫秒级的时间戳。因为@Field注解在这里可能是来自Elasticsearch的映射注解。FieldType.Date表示这个字段是日期类型,而format = DateFormat.epoch_millis 说明日期是以毫秒数存储的
Elasticsearch Java客户端
代码现状分析
result.setClientTime(data.getClientTime()); // 直接传递Date对象
@Field(type = FieldType.Date, format = DateFormat.epoch_millis) // 却声明需要毫秒时间戳格式
private Date clientTime;
这里存在Date对象与毫秒时间戳格式声明的冲突,可能导致序列化异常(如Elasticsearch无法解析Date对象格式)。
问题根因定位
- 数据类型不匹配
- Date对象默认序列化后是ISO8601字符串(如2025-03-28T11:02:00.000+08:00)
- epoch_millis格式要求数值型时间戳(如1745809320000)
- 框架行为差异
- Elasticsearch Java客户端不会自动转换Date对象
- 需要显式处理时间格式转换
解决方案建议
方案一:统一使用Long类型存储
// 字段定义
@Field(type = FieldType.Date, format = DateFormat.epoch_millis)
private Long clientTime; // 改为Long类型
// 赋值操作
result.setClientTime(data.getClientTime().getTime()); // 获取毫秒时间戳
优势:彻底规避类型转换问题