news 2026/4/18 10:43:22

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/4/18 7:53:01

深求·墨鉴使用技巧:提升手写笔记识别准确率

深求墨鉴使用技巧&#xff1a;提升手写笔记识别准确率 1. 为什么手写笔记识别总是“差一点”&#xff1f; 你有没有过这样的经历&#xff1a; 拍下一页密密麻麻的课堂笔记&#xff0c;满怀期待地点击「研墨启笔」&#xff0c;结果生成的文字里—— “微积分”变成了“微积风”…

作者头像 李华
网站建设 2026/4/18 8:52:03

文脉定序应用实践:客服工单知识匹配中重排序模块降低误判率42%

文脉定序应用实践&#xff1a;客服工单知识匹配中重排序模块降低误判率42% 1. 项目背景与挑战 在客服工单处理场景中&#xff0c;知识匹配的准确性直接关系到问题解决效率和客户满意度。传统的关键词匹配和基础向量检索虽然能够快速找到相关文档&#xff0c;但经常出现"…

作者头像 李华
网站建设 2026/4/18 7:52:59

SenseVoice-Small ONNX模型绿色计算:语音识别任务碳足迹测算与优化

SenseVoice-Small ONNX模型绿色计算&#xff1a;语音识别任务碳足迹测算与优化 1. 语音识别模型的碳足迹挑战 语音识别技术在日常生活中的应用越来越广泛&#xff0c;从智能助手到客服系统&#xff0c;从会议转录到语音输入&#xff0c;无处不在的语音识别服务背后是巨大的计…

作者头像 李华
网站建设 2026/4/18 8:40:55

YOLO12性能实测:注意力架构带来的精度飞跃

YOLO12性能实测&#xff1a;注意力架构带来的精度飞跃 1. 引言&#xff1a;为什么这次升级值得你关注&#xff1f; 你是否遇到过这样的困扰&#xff1a;在工业质检场景中&#xff0c;微小缺陷漏检率高&#xff1b;在自动驾驶视频流里&#xff0c;密集车辆检测框重叠严重&…

作者头像 李华
网站建设 2026/4/18 7:59:04

开箱即用!Ollama部署Llama-3.2-3B的完整教程

开箱即用&#xff01;Ollama部署Llama-3.2-3B的完整教程 想快速体验一个功能强大的开源大模型&#xff0c;但又担心复杂的安装配置和环境依赖&#xff1f;今天&#xff0c;我们就来手把手教你&#xff0c;如何在几分钟内&#xff0c;通过Ollama这个“神器”&#xff0c;零门槛…

作者头像 李华
网站建设 2026/4/17 23:34:52

LongCat-Image-Edit创意玩法:让宠物照片秒变艺术品

LongCat-Image-Edit创意玩法&#xff1a;让宠物照片秒变艺术品 你是不是也和我一样&#xff0c;手机里存满了自家“毛孩子”的照片&#xff1f;从呆萌的睡姿到搞怪的表情&#xff0c;每一张都想珍藏&#xff0c;但又总觉得少了点新意。直接发朋友圈吧&#xff0c;好像有点普通…

作者头像 李华