
在现代java应用中,处理日期和时间数据通常推荐使用java.time包(jsr 310)中的类型,如localdatetime、localdate和instant,它们提供了更强大、更清晰的api。然而,当从外部rest服务接收json数据时,时间戳常以epoch毫秒(自1970年1月1日00:00:00 utc以来的毫秒数)的形式表示。直接尝试将这种长整型时间戳反序列化为localdatetime或localdate时,jackson库会抛出错误,例如“raw timestamp (...) not allowed for java.time.localdatetime: need additional information such as an offset or time-zone”或“invalid value for epochday”。这是因为localdatetime不包含时区信息,而epoch毫秒是一个带有隐含时区(utc)的绝对时间点。localdate则更进一步,仅表示日期,直接从epoch毫秒转换需要精确的时区和日期计算。
本文将详细介绍几种解决此问题的有效策略。
一种直接的方法是在目标数据类的构造函数中手动处理时间戳的转换。这种方法允许对单个类进行精确控制,适用于不希望引入全局配置或自定义反序列化器的场景。
实现步骤:
示例代码:
立即学习“Java免费学习笔记(深入)”;
假设我们希望将JSON中的creation_date字段(Epoch毫秒)反序列化到MyLocalApplicationClass的LocalDateTime creationDate字段。
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
public class MyLocalApplicationClass {
private String name;
private LocalDateTime creationDate;
private String createdBy;
// 无参构造函数(或其他构造函数),如果需要的话
public MyLocalApplicationClass() {
}
// 带有@JsonProperty注解的全参数构造函数,用于Jackson反序列化
public MyLocalApplicationClass(@JsonProperty("name") String name,
@JsonProperty("creation_date") long creationDate,
@JsonProperty("created_by") String createdBy) {
this.name = name;
this.createdBy = createdBy;
// 将Epoch毫秒转换为LocalDateTime,假设时间戳是UTC时间
this.creationDate = Instant
.ofEpochMilli(creationDate)
.atZone(ZoneOffset.UTC) // 明确指定时区,通常是UTC
.toLocalDateTime();
}
// Getters and Setters (省略)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public LocalDateTime getCreationDate() { return creationDate; }
public void setCreationDate(LocalDateTime creationDate) { this.creationDate = creationDate; }
public String getCreatedBy() { return createdBy; }
public void setCreatedBy(String createdBy) { this.createdBy = createdBy; }
}注意事项:
对于Spring Boot应用,可以通过配置ObjectMapper实现全局的时间戳处理。这种方法更具侵入性,但一旦配置,所有符合条件的字段都会自动处理,减少了重复代码。
实现步骤:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.x.x</version> <!-- 替换为Jackson版本 -->
</dependency>示例代码:
立即学习“Java免费学习笔记(深入)”;
首先,修改MyLocalApplicationClass,将creationDate的类型改为Instant:
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.Instant;
public class MyLocalApplicationClass {
private String name;
@JsonProperty("creation_date") // 如果JSON字段名与Java字段名不匹配,仍需此注解
private Instant creationDate;
@JsonProperty("created_by")
private String createdBy;
// Getters and Setters (省略)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Instant getCreationDate() { return creationDate; }
public void setCreationDate(Instant creationDate) { this.creationDate = creationDate; }
public String getCreatedBy() { return createdBy; }
public void setCreatedBy(String createdBy) { this.createdBy = createdBy; }
}然后,配置ObjectMapper。
方法一:通过配置类(适用于非Spring Boot或需要更细粒度控制的场景)
Easily find JSON paths within JSON objects using our intuitive Json Path Finder
30
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
@Configuration
public class JsonConfig {
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder();
}
@Bean
public ObjectMapper objectMapper() {
return jackson2ObjectMapperBuilder()
.build()
.registerModule(new JavaTimeModule()) // 注册JavaTime模块
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false); // 将时间戳视为毫秒
}
}方法二:通过application.properties(Spring Boot推荐)
在Spring Boot应用中,JacksonAutoConfiguration会自动检测并注册JavaTimeModule。我们只需通过配置文件来设置DeserializationFeature。
# application.properties 或 application.yml spring.jackson.deserialization.read-date-timestamps-as-nanoseconds=false
使用这种方式,你无需定义上述的JsonConfig类中的ObjectMapper和Jackson2ObjectMapperBuilder Bean。Spring Boot会自动为你配置。
注意事项:
如果前两种方法不适用,例如你必须将时间戳反序列化为LocalDateTime而不是Instant,或者需要更复杂的转换逻辑,可以实现一个自定义的Jackson反序列化器。
实现步骤:
示例代码:
立即学习“Java免费学习笔记(深入)”;
首先,定义自定义反序列化器:
import com.fasterxml.jackson.core.JacksonException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
public class DateTimeDeserializer extends StdDeserializer<LocalDateTime> {
public DateTimeDeserializer() {
super(LocalDateTime.class);
}
@Override
public LocalDateTime deserialize(JsonParser p,
DeserializationContext ctxt) throws IOException, JacksonException {
JsonNode node = p.getCodec().readTree(p);
long timestamp = node.longValue(); // 获取Epoch毫秒值
return Instant
.ofEpochMilli(timestamp)
.atZone(ZoneOffset.UTC) // 同样,明确指定时区
.toLocalDateTime();
}
}然后,在MyLocalApplicationClass中应用此反序列化器:
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.time.LocalDateTime;
public class MyLocalApplicationClass {
private String name;
@JsonDeserialize(using = DateTimeDeserializer.class) // 应用自定义反序列化器
@JsonProperty("creation_date")
private LocalDateTime creationDate;
@JsonProperty("created_by")
private String createdBy;
// Getters and Setters (省略)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public LocalDateTime getCreationDate() { return creationDate; }
public void setCreationDate(LocalDateTime creationDate) { this.creationDate = creationDate; }
public String getCreatedBy() { return createdBy; }
public void setCreatedBy(String createdBy) { this.createdBy = createdBy; }
}注意事项:
将REST响应中的Epoch毫秒时间戳反序列化为java.time类型是常见的需求。根据你的具体场景和偏好,可以选择以下策略:
无论选择哪种方法,关键在于理解java.time类型与Epoch毫秒之间的转换关系,特别是时区(ZoneOffset.UTC是常用选择)在转换过程中的作用,以确保日期时间数据的准确性。
以上就是处理JSON时间戳:将Epoch毫秒转换为java.time类型的策略的详细内容,更多请关注php中文网其它相关文章!
java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号