REST响应的Date属性能否直接转为LocalDateTime或LocalDate?
类结构与返回数据
本地应用类
public class MyLocalApplicationClass { private String name; private LocalDateTime creationDate; private String createdBy; }
远程REST服务对应类结构
public class MyRemoteApplicationClass { private String name; private Date creationDate; private String createdBy; }
实际返回的JSON示例
{ "name": "anything", "creation_date": 1666190973000, "created_by": "anyone" }
核心疑问
能否直接将上述时间戳接收为LocalDateTime类型,还是必须先接收为Date再转为LocalDateTime?
尝试过程及错误信息
尝试直接反序列化为LocalDateTime
抛出错误:
raw timestamp (1656015404000) not allowed for java.time.LocalDateTime: need additional information such as an offset or time-zone (see class Javadocs)
翻译:
原始时间戳(1656015404000)无法反序列化为
java.time.LocalDateTime:需要额外信息,例如偏移量或时区(详见类文档)
尝试反序列化为LocalDate
已添加jsr310依赖,并使用注解@JsonSerialize(using = LocalDateSerializer.class) @JsonDeserialize(using = LocalDateDeserializer.class),仍抛出如下错误及警告:
Java 8 date/time type `java.time.DateTimeException` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling (through reference chain: com.fasterxml.jackson.databind.JsonMappingException["cause"]) WARN -- com.fasterxml.jackson.databind.JsonMappingException: Invalid value for EpochDay (valid values -365243219162 - 365241780471): 1656015404000
翻译:
默认不支持Java 8日期/时间类型
java.time.DateTimeException:请添加模块com.fasterxml.jackson.datatype:jackson-datatype-jsr310以启用处理(引用链:com.fasterxml.jackson.databind.JsonMappingException["cause"])警告 -- com.fasterxml.jackson.databind.JsonMappingException: EpochDay值无效(有效值范围为 -365243219162 至 365241780471):1656015404000
解决方案
可以直接将时间戳反序列化为LocalDateTime,无需先转换为Date。报错的核心原因是LocalDateTime本身不包含时区信息,而时间戳是基于UTC的绝对时间,必须指定时区/偏移量才能完成转换。具体实现如下:
1. 确认依赖配置
确保项目中已引入Jackson的JSR310模块(以Maven为例):
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>你的Jackson版本号</version> </dependency>
2. 配置反序列化规则
有两种常用方式:
方式一:全局配置(推荐)
在ObjectMapper中全局注册JSR310模块,并指定默认时区,让所有时间戳反序列化时使用该时区转换为LocalDateTime:
ObjectMapper objectMapper = new ObjectMapper(); // 注册Java 8日期时间模块 objectMapper.registerModule(new JavaTimeModule()); // 设置默认时区,可根据需求选择UTC或系统时区 objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); // 允许将日期调整为上下文时区 objectMapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, true);
方式二:字段级注解
在LocalDateTime字段上添加注解,明确指定反序列化时的时区:
public class MyLocalApplicationClass { private String name; @JsonFormat(shape = JsonFormat.Shape.NUMBER, timezone = "UTC") private LocalDateTime creationDate; private String createdBy; }
或者自定义反序列化器,手动将时间戳转换为LocalDateTime:
public class TimestampToLocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> { @Override public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { long timestamp = p.getLongValue(); // 这里可替换为业务需要的时区,比如ZoneId.systemDefault() return Instant.ofEpochMilli(timestamp) .atZone(ZoneId.of("UTC")) .toLocalDateTime(); } }
然后在字段上引用该反序列化器:
@JsonDeserialize(using = TimestampToLocalDateTimeDeserializer.class) private LocalDateTime creationDate;
关于LocalDate尝试失败的说明
报错的原因是LocalDateDeserializer默认将数字解析为自纪元以来的天数,而传入的是毫秒级时间戳,数值远超出EpochDay的有效范围。如果需要将时间戳转为LocalDate,同样需要自定义反序列化逻辑,先将时间戳转为Instant,再指定时区转换为LocalDate。
内容的提问来源于stack exchange,提问作者BugsOverflow

