news 2026/9/8 15:44:58

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/8/25 10:16:15

Qwen2.5-0.5B实测:轻量级模型的强大对话能力展示

Qwen2.5-0.5B实测&#xff1a;轻量级模型的强大对话能力展示 1. 引言 在AI大模型快速发展的今天&#xff0c;很多人都有一个疑问&#xff1a;小参数模型真的能用吗&#xff1f;0.5B参数的模型能做什么&#xff1f;今天我们就来实测阿里巴巴最新推出的Qwen2.5-0.5B-Instruct模…

作者头像 李华
网站建设 2026/8/28 19:52:49

33种语言自由切换:Hunyuan-MT Pro多语言翻译实战测评

33种语言自由切换&#xff1a;Hunyuan-MT Pro多语言翻译实战测评 1. 引言&#xff1a;当翻译遇上大模型&#xff0c;会擦出什么火花&#xff1f; 想象一下这个场景&#xff1a;你正在处理一份多语种的国际项目文档&#xff0c;里面有英文的技术规范、日文的供应商邮件、法文的…

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

Qwen3-TTS实战:用AI语音为视频配音的完整教程

Qwen3-TTS实战&#xff1a;用AI语音为视频配音的完整教程 1. 为什么你需要这个教程&#xff1a;告别配音烦恼&#xff0c;3分钟搞定专业级旁白 你是不是也遇到过这些情况&#xff1f; 做完一个精心剪辑的科普视频&#xff0c;却卡在配音环节——自己录音声音干瘪、反复重录耗…

作者头像 李华
网站建设 2026/9/2 2:27:08

手把手教你用RexUniNLU实现中文文本分类

手把手教你用RexUniNLU实现中文文本分类 如果你正在寻找一个能快速上手、无需标注数据就能完成各种中文NLP任务的工具&#xff0c;那么RexUniNLU绝对值得你花时间了解。想象一下这样的场景&#xff1a;老板突然让你分析一批用户评论的情感倾向&#xff0c;或者需要从大量新闻中…

作者头像 李华