Java JAX-RS接口响应中Date自动时间转换的原因及解决方法
问题1:自动时间转换的触发位置与禁止方法
该转换发生在JAX-RS返回对象序列化为JSON响应的阶段,由JSON序列化库(绝大多数JAX-RS实现默认使用Jackson作为序列化Provider)触发。java.util.Date本身仅存储时间戳,不携带时区信息,序列化时会按照序列化库配置的时区,将时间戳转换为对应时区的日期字符串。默认情况下Jackson序列化Date时会使用UTC时区输出,若你的JVM默认时区为UTC+5:30(即印度标准时间),就会出现你观察到的差值:断点、日志中看到的是JVM时区下的时间,序列化后输出的是UTC时区的时间,二者刚好相差5小时30分。
禁止自动转换可以用以下两种方案:
- 全局配置:自定义JAX-RS的
ObjectMapper提供者,显式指定序列化时区,示例代码如下:
@Provider public class CustomObjectMapperProvider implements ContextResolver<ObjectMapper> { private final ObjectMapper objectMapper; public CustomObjectMapperProvider() { objectMapper = new ObjectMapper(); // 配置使用JVM默认时区序列化日期 objectMapper.setTimeZone(TimeZone.getDefault()); // 也可固定指定时区,比如固定为UTC:objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); // 同时可以统一指定日期输出格式 objectMapper.setDateFormat(new SimpleDateFormat("dd-MM-yyyy HH:mm:ss")); } @Override public ObjectMapper getContext(Class<?> type) { return objectMapper; } }
- 单字段配置:在
createdAt字段上添加Jackson注解,单独指定序列化的格式与时区,无需修改全局配置:
class User{ private int id; private String name; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy HH:mm:ss", timezone = "IST") private Date createdAt; }
将timezone属性值替换为你实际需要的时区即可。
问题2:日期时间库替代方案
推荐使用Java 8及以上版本内置的java.time(JSR310)库替代老旧的java.util.Date:
- 存储不需要时区信息的本地时间可以用
LocalDateTime - 存储带时区信息的时间可以用
ZonedDateTime - 存储标准时间戳可以用
Instant
java.time下的类都是不可变、线程安全的,明确区分了不同的时间使用场景,不会出现Date类无时区属性导致的隐式转换问题。使用时只需引入Jackson的jackson-datatype-jsr310模块,即可支持该包下类的序列化,同样可以通过上述全局配置或者字段注解指定格式与时区。
内容的提问来源于stack exchange,提问作者Jyoti Singh
相关产品推荐
相关产品推荐

