news 2026/6/10 18:10:37

Spring Boot日期格式注解@DateTimeFormat和@JsonFormat的区别与应用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot日期格式注解@DateTimeFormat和@JsonFormat的区别与应用

@DateTimeFormat@JsonFormat是 Spring Boot 中处理日期时间格式化的两个常用注解,但它们的用途和工作场景不同。

@DateTimeFormat

用途

主要用于Spring MVC 参数绑定,处理表单提交、URL参数、请求参数中的日期时间字符串转换。

使用场景

java

@Controller public class MyController { // 处理URL参数 /api/data?date=2023-01-01 @GetMapping("/api/data") public String getData(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date date) { return "success"; } // 处理表单提交 @PostMapping("/api/form") public String submitForm(@ModelAttribute FormData form) { return "success"; } } public class FormData { // 将前端传来的字符串 "2023-01-01" 转换为 Date 对象 @DateTimeFormat(pattern = "yyyy-MM-dd") private Date birthDate; }

特点

  1. Spring 框架注解:属于org.springframework.format.annotation

  2. 入参格式化:主要用于将 HTTP 请求中的字符串参数转换为 Java 日期对象

  3. 支持简单模式

    java

    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @DateTimeFormat(iso = ISO.DATE) // ISO 标准格式

@JsonFormat

用途

主要用于JSON 序列化和反序列化,处理 JSON 数据与 Java 对象之间的转换。

使用场景

java

@RestController public class UserController { @GetMapping("/user") public User getUser() { User user = new User(); user.setCreateTime(new Date()); // 返回时会按照指定格式序列化 return user; } @PostMapping("/user") public User createUser(@RequestBody User user) { // 前端传入的JSON中的日期字符串会被反序列化为Date对象 return user; } } public class User { // JSON序列化和反序列化都使用此格式 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date createTime; }

特点

  1. Jackson 注解:属于com.fasterxml.jackson.annotation

  2. 双向转换:既用于序列化(对象 → JSON),也用于反序列化(JSON → 对象)

  3. 需要指定时区:通常需要明确指定timezone

  4. 配置更灵活

    java

    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "Asia/Shanghai") @JsonFormat(shape = JsonFormat.Shape.STRING) // 强制序列化为字符串

主要区别对比

特性@DateTimeFormat@JsonFormat
所属框架Spring FrameworkJackson
主要用途HTTP参数绑定JSON序列化/反序列化
方向单向(字符串→对象)双向(字符串↔对象)
是否需要时区通常不需要强烈建议指定
处理阶段请求参数绑定阶段JSON转换阶段
适用范围Controller参数、表单对象实体类字段、DTO字段

实际应用示例

场景1:前后端分离的REST API

java

@Data public class OrderDTO { // 用于JSON序列化/反序列化 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date orderTime; // 用于URL参数或表单提交 @DateTimeFormat(pattern = "yyyy-MM-dd") private Date deliveryDate; } @RestController @RequestMapping("/api/orders") public class OrderController { // GET /api/orders?startDate=2023-01-01&endDate=2023-12-31 @GetMapping public List<OrderDTO> getOrders( @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date startDate, @RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") Date endDate) { // 查询逻辑 } // POST JSON: {"orderTime": "2023-12-01 14:30:00"} @PostMapping public OrderDTO createOrder(@RequestBody OrderDTO orderDTO) { // @JsonFormat 会自动将字符串转换为Date return orderDTO; } }

场景2:同时使用两个注解

java

@Data public class Event { // 同时支持表单提交和JSON转换 @DateTimeFormat(pattern = "yyyy-MM-dd") @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") private Date eventDate; }

配置建议

全局配置替代方案

  1. 全局日期格式化(application.yml)

yaml

spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT+8
  1. 自定义Converter

java

@Configuration public class DateConfig { @Bean public Converter<String, Date> stringToDateConverter() { return new Converter<String, Date>() { @Override public Date convert(String source) { try { return new SimpleDateFormat("yyyy-MM-dd").parse(source); } catch (ParseException e) { return null; } } }; } }

总结建议

  1. 使用 @DateTimeFormat

    • 处理表单提交

    • URL查询参数

    • @RequestParam@ModelAttribute绑定的参数

  2. 使用 @JsonFormat

    • REST API 的请求体(@RequestBody)

    • 响应体的序列化

    • 需要双向转换的场景

  3. 最佳实践

    • 在 REST API 开发中,主要使用@JsonFormat

    • 在传统的表单提交应用中,主要使用@DateTimeFormat

    • 考虑统一格式时,可以在配置文件中设置全局格式,减少注解使用

  4. 注意事项

    • 时区问题:@JsonFormat必须指定时区,否则可能造成时间错误

    • 格式一致性:前后端约定的日期格式要保持一致

    • 性能考虑:过多的注解可能影响性能,考虑使用全局配置


@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 这里最好是用GMT+8还是Asia/Shanghai

强烈推荐使用Asia/Shanghai,而不是GMT+8

为什么推荐使用Asia/Shanghai

1.历史兼容性和准确性

java

// 不推荐 - 硬编码偏移量 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") // 推荐 - 使用时区标识 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")

历史原因:中国历史上曾实行过夏令时(1986-1991年),虽然现在没有,但使用地区时区标识更准确。

2.更清晰的语义

java

// GMT+8 可能有歧义 // 哪些地区使用GMT+8? // - 中国(北京时间) // - 新加坡 // - 马来西亚 // - 菲律宾 // - 澳大利亚西部时间(部分) // - 俄罗斯部分地区 // Asia/Shanghai 明确指代中国标准时间

3.Java时区系统的推荐做法

java

// Java Time API 推荐使用地区时区 ZoneId zone1 = ZoneId.of("Asia/Shanghai"); // ✅ 推荐 ZoneId zone2 = ZoneId.of("GMT+8"); // ❌ 不推荐 // Spring Boot 配置也是使用地区时区 spring.jackson.time-zone: Asia/Shanghai

实际差异演示

示例代码

java

@Data class TestDate { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") private Date date1; @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date date2; // Java 8+ 推荐使用 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private LocalDateTime date3; } // 测试代码 @Test public void testTimezone() { TestDate test = new TestDate(); // 同一个时间点 test.setDate1(new Date(1640995200000L)); // 2022-01-01 00:00:00 UTC test.setDate2(new Date(1640995200000L)); // 序列化结果 // date1: "2022-01-01 08:00:00" (GMT+8) // date2: "2022-01-01 08:00:00" (Asia/Shanghai) // 表面看起来一样,但内部处理不同 }

可能的问题场景

java

// 假设未来中国恢复夏令时(虽然可能性不大) // Asia/Shanghai 会自动处理,GMT+8 不会 // 历史日期处理 Date historicalDate = // 1989-06-04(中国实行夏令时期) // Asia/Shanghai: 正确考虑夏令时偏移 // GMT+8: 固定偏移,可能错误

最佳实践配置

1.实体类/DTO配置

java

@Data public class UserDTO { // ✅ 推荐 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date createTime; // ✅ Java 8+ 时间API @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", shape = JsonFormat.Shape.STRING) private LocalDateTime updateTime; // LocalDateTime不需要时区,因为它没有时区信息 }

2.全局配置(application.yml)

yaml

spring: jackson: # 全局日期格式 date-format: yyyy-MM-dd HH:mm:ss # ✅ 使用地区时区 time-zone: Asia/Shanghai serialization: write-dates-as-timestamps: false

3.Controller中处理时区

java

@RestController public class TimeController { // 允许客户端传递时区参数 @GetMapping("/time") public ResponseEntity<?> getTime( @RequestParam(value = "timezone", defaultValue = "Asia/Shanghai") String timezone) { // 动态使用时区 ObjectMapper mapper = new ObjectMapper(); mapper.setTimeZone(TimeZone.getTimeZone(timezone)); // ... 返回数据 } }

特殊情况处理

1.多时区应用

java

// 存储UTC时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC") private Date utcTime; // 展示时根据用户时区转换 public String formatForUser(Date date, String userTimezone) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); sdf.setTimeZone(TimeZone.getTimeZone(userTimezone)); return sdf.format(date); }

2.与时区无关的时间

java

// 只关心日期,不关心时区 @JsonFormat(pattern = "yyyy-MM-dd") private Date birthDate; // 生日不需要时区 // Java 8 LocalDate 更好 @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate birthDate;

总结建议

使用原则:

  1. 中国地区应用:始终使用Asia/Shanghai

  2. 国际应用:存储使用UTC,展示时按需转换

  3. Java 8+:优先使用LocalDateTimeLocalDate,避免时区问题

代码示例对比:

java

// ❌ 不推荐 - 硬编码偏移量 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") // ✅ 推荐 - 地区时区标识 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") // ✅ 最优 - Java 8时间API(无时区问题) @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime localTime; // ✅ 全局配置替代注解 // 在application.yml中配置,减少重复注解

关键点Asia/ShanghaiGMT+8更语义化、更规范、更具未来兼容性。虽然在当前中国时区政策下结果相同,但作为专业开发者应该使用更标准的做法。


注解

核心作用

生效阶段

依赖框架

核心场景

@DateTimeFormat

格式化入参

前端→后端(接收参数)

Spring MVC

接收前端传的日期字符串(如2024-05-20),转成Date/LocalDateTime

@JsonFormat

格式化出参

后端→前端(返回数据)

Jackson

把后端的Date/LocalDateTime转成指定格式的字符串返回给前端

简单说:

  • • 想让前端传的日期字符串能被后端正确接收,用@DateTimeFormat;

  • • 想让后端返回的日期不是时间戳/乱码,而是指定格式(如yyyy-MM-dd HH:mm:ss),用@JsonFormat;

  • • 既想收参正常,又想返参格式对,就两个注解一起用(但要注意细节)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 14:11:57

Spring Boot 日期范围(查询专用DTO)

以下spring boot 项目代码&#xff1a; package com.weiyu.model;import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.validation.constraints.AssertTrue; import jakarta.validation.constraints.Pat…

作者头像 李华
网站建设 2026/6/9 22:50:05

惊艳!Qwen3-TTS生成10国语言语音效果实测

惊艳&#xff01;Qwen3-TTS生成10国语言语音效果实测 获取更多AI镜像 想探索更多AI镜像和应用场景&#xff1f;访问 CSDN星图镜像广场&#xff0c;提供丰富的预置镜像&#xff0c;覆盖大模型推理、图像生成、视频生成、模型微调等多个领域&#xff0c;支持一键部署。 1. 前言&a…

作者头像 李华
网站建设 2026/6/10 1:46:48

保姆级LongCat-Image-Edit指南:手把手教你图片魔法编辑

保姆级LongCat-Image-Edit指南&#xff1a;手把手教你图片魔法编辑 1. 这不是修图软件&#xff0c;是你的AI图像魔法师 你有没有试过——想把一张普通宠物照变成赛博朋克风格的机械猫&#xff0c;或者让家里的橘猫瞬间穿上宇航服漂浮在火星表面&#xff1f;传统修图工具要调图…

作者头像 李华
网站建设 2026/6/10 13:18:19

摄影工作室降本提效:cv_unet_image-colorization批量黑白图上色方案

摄影工作室降本提效&#xff1a;cv_unet_image-colorization批量黑白图上色方案 1. 项目简介 在摄影工作室的日常工作中&#xff0c;经常会遇到需要处理黑白照片的场景。无论是修复老照片&#xff0c;还是为艺术创作中的黑白作品上色&#xff0c;传统的手工上色方式既耗时又成…

作者头像 李华
网站建设 2026/6/10 14:11:47

DAMO-YOLO实战技巧:如何优化工业检测性能

DAMO-YOLO实战技巧&#xff1a;如何优化工业检测性能 1. 工业场景下的真实挑战&#xff1a;为什么标准YOLO不够用 在工厂产线、仓储分拣、电力巡检等工业视觉任务中&#xff0c;我们常遇到这样一组矛盾组合&#xff1a;既要识别毫米级螺丝缺陷&#xff0c;又要实时处理4K分辨…

作者头像 李华