我的编程空间,编程开发者的网络收藏夹
学习永远不晚

@DateTimeFormat 和 @JsonFormat 注解详解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

@DateTimeFormat 和 @JsonFormat 注解详解

这一篇文章足以让你对Java当中Date时间上的理解更上一层楼,本篇文章主要通过代码的形式来进行试验,彻彻底底搞明白日期传参,以及日期返回参数的格式相关问题,每一个步骤都会记得特别详细!

本篇文章主要针对以下三点,来进行代码试验:

  1. 不使用这两个注解,前端传参和后端返回参数 格式是什么样的?
  2. @DateTimeFormat究竟在什么时候用?
  3. @JsonFormat在什么时候用?
  4. 二者有什么区别?

目录

总结

如果想要看详细测试过程的,可以看下面的每一步骤,如果着急要结果的,看总结足矣!

@DateTimeFormat和@JsonFormat都是处理时间格式化问题的!

区别@DateTimeFormat@JsonFormat
使用方法@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
使用场景URL传参时,格式化前端传向后端日期类型的时间格式JSON传参,格式化前端传参和后端返回给前端的时间格式,传参可能不一定是json,但是一般接口向前端返回数据,基本上都是封装的统一返回格式,然后JSON返回。所以这个注解是一定要加的!
使用地方实体类日期字段上、或者字段的set方法上、或者方法入参上实体类日期字段上、或者字段的set方法上、、或者方法入参上
来源org.springframework.format.annotationcom.fasterxml.jackson.annotation

注意:

  1. 一旦使用yyyy-MM-dd 格式,如果传时分秒就会报错,或者是使用 yyyy-MM-dd HH:mm:ss,如果传yyyy-MM-dd 也会报错。
  2. 假如是springboot项目的话,使用这两个注解是不用导其他的依赖包的!
  3. 框架当中默认他会认为 前端传的是UTC时间,然后SpringMVC在接到参数的时候,会进行转换为本地区时间,向前端返回参数的时候会转换为UTC时间!
  4. 这两个注解可以选择在实体类的set方法当中使用,也可以在字段上使用,效果是一样的!

一、不使用注解

首先准备一张表:时间我使用的mysql是datetime类型,存储到数据库的格式是 yyyy-MM-dd HH:mm:ss

注意这个格式是mysql的DATETIME字段类型格式,也就是我们使用mybatis也好,plus也罢,只要是日期类型,不管传的时候是什么格式,存到数据库之后都会变成这个格式!

CREATE TABLE `student`  (  `id` int(11) NOT NULL AUTO_INCREMENT,  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,  `create_date` datetime NULL DEFAULT NULL,  `upload_date` datetime NULL DEFAULT NULL,  PRIMARY KEY (`id`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

实体类:我用的是mybatis-plus框架做的试验,本篇mybatis-plus不是重点,重点要看的是日期类型格式

@TableName(value = "student")@Data@ToString(callSuper = true)public class Student implements Serializable {    @TableId(type = IdType.AUTO)    private Integer id;    @TableField(value = "name")    private String name;    @TableField(value = "create_date")    private Date createDate;    @TableField(value = "upload_date")    private Date uploadDate;}

controller代码:这里准备了一个接口,然后是用的post的json传参,前端传一个uploadDate日期字段,然后后端在new 一个Date,最终还将对象返回给了前端,这样做的目的就是看 前端传参 以及 后端返回 时候的日期类型格式。

还有一个接口就是通过Get请求params传参。

@RequestMapping("student")@RestControllerpublic class StudentController {    @Autowired    private StudentService studentService;    @PostMapping("/add")    public Student add(@RequestBody Student student) {    // 前端假如要是传yyyy-MM-dd不传时分秒,会按照UTC世界时间传,但是后端以Date类型去接参,会将时间转换成当前时区的时间        System.out.println(student.getUploadDate());        student.setCreateDate(new Date());        studentService.save(student);        return student;    }        @GetMapping("/getByStudent")    public Student getByStudent(Student student) {        System.out.println(student);        return student;    }}

使用的是mysql数据库

spring:  datasource:    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false    password: root    username: root

1.1. Json传参测试

测试一:通过postman调用,观察不使用这两个注解,前端传参和后端返回参数 格式是什么样的?

控制台打印的也是类似于如下格式:System.out.println(student.getUploadDate());

在这里插入图片描述

查询数据库,如下:

注意前端传的uploadDate只传了年月日,到数据库也会自动补齐时分秒,而且补的还是8点。

这里还有一个细节问题,数据库保存的是2022-09-15 22:40:50,反给前端的是2022-09-15T14:40:50.000+00:00,显然时间上是相差8个小时的!是框架出bug了?当然不是,反给前端的不是标准的时间而是世界时的IOS时间格式!关于这个后面会讲~!

在这里插入图片描述

测试二:假如前端传值格式为:2022/09/12,直接报400参数类型错误!

测试三:假如前端传值格式为:2022-09-12 08:00:00,也会直接报400参数类型错误!

不使用任何注解的时候,总结如下:

  1. 假如接口用的Date类型字段接值,前端传参只能传yyyy-MM-dd 格式,假如传yyyy-MM-dd HH:mm:ss 或者yyyy/MM/dd 是都会报400错误的!
  2. 假如使用的mysql的DATETIME类型,前端传的是yyyy-MM-dd 格式 这时候数据库当中会自动补齐时分秒 yyyy-MM-dd 08:00:00
    原因:没有声明时分秒的时候,他会默认按照世界时传过来,但是当使用Date类型来接的时候,Date会根据时区,将世界时进行转换为当前时区的时间,最终存储到数据库的就是 yyyy-MM-dd 08:00:00
  3. 没有使用注解的情况下,后端向前端返回日期类型字段的格式是:2022-09-15T14:40:50.000+00:00(世界时的IOS的格式),当我们使用System.out.println(new Date()); 单独输出日期,格式是:Thu Sep 15 23:24:01 CST 2022,会发现两个压根不是一个东西。
    原因:在后端当中,所有相关日期都是当前时区的时间,但是一旦涉及到向前端返回数据,都会转换为utc世界时间,要知道Java不止咱们国家在用。
  4. 数据库保存的是2022-09-15 22:40:50,反给前端的是2022-09-15T14:40:50.000+00:00,这个格式是ios时间格式,也就是在不使用注解的情况,反给前端的时候使用的是世界时IOS格式。世界UTC时间和中国时间有八个小时的时差!

1.2. Params传参测试

测试一:传yyyy-MM-dd 或者传 yyyy-MM-dd HH:mm:ss 都会报400错误!

二、Date格式问题

想要搞明白日期格式化问题,首先要明白Date类,Date类是java.util包中的基础类。当我们通过System.out.println(new Date()); 输出的时候,格式如下:这个格式是Date类的toString定的日期格式化!
星期 月份 日期 时:分:秒 时区 年份
Thu Sep 15 23:24:01 CST 2022

格式化Date格式:

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EE");System.out.println(simpleDateFormat.format(new Date()));

2.1. ISO

国际标准ISO 8601,是国际标准化组织的日期和时间的表示方法,2022-09-15T14:40:50.000+00:00 就是典型的ISO格式,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。

ISO 8601日期格式如下:YYYY-MM-DDThh:mm:ss[.mmm]TZD

  • YYYY表示四位数的年份
  • MM表示两位数的月份
  • DD表示两位数的天(day of the month),从01到31
  • T是用来指示时间元素的开始字符
  • hh表示两位数的小时,从00到23,不包括AM/PM
  • mm表示两位数的分钟,从00到59
  • ss表示两位数的秒,从00到59
  • mmm表示三位数的毫秒数,从000到999
  • TZD表示时区指示符:Z 或 +hh:mm 或 -hh:mm ,+ 或- 表示时区距离UTC(世界标准时间)时区多远。例如:2022-09-15T14:40:50.000+00:00,中国时间和世界时间相差8个小时,假如中国时间就是2022-09-15T14:40:50.000+08:00

2.2. GMT

它是世界时又叫格林尼治标准时间(格林尼治所在地的标准时间);格林尼治在英国伦敦,那里有一条非常著名的线,叫本初子午线;世界计算时间的起点(时区的划分)以及经度的起点就是这条线。

格林尼治(Greenwich),是英国伦敦的一个区,位于伦敦东南、泰晤士河南岸。

地球分为24 个时区,一个时区的范围是十五个经度,地球又分东西半球,东西半球各占十二个时区;每个时区相差一个小时,最多相差24小时,也就是一天。凡向西走,每过一个时区,时间要慢一个小时,就要把表拨慢1小时(就是说你所在的位置是两点,向西一个时区就减去一个小时,也就是一点);凡向东走,每过一个时区,时间要快一个小时,就要把表拨快1小时(比如1点拨到2点)。格林尼治天文台所在的地方叫零时区。零时区表示为GMT+00,零时区缩写叫z

以格林尼治天文台所在的时区为中心(GMT+00),向东为正,向西为负;零时区比东时区晚,比西时区早。0时区比东八区的时间晚8小时,比西五区的时间早5小时。美国华盛顿比北京慢13小时;
  
在中国以北京所在的区统一时间,北京所在的时区叫东八区,东八区表示形式是:GMT+08;
美国常用美东时间来表示,美东时间表示纽约、华盛顿所在的时区,那个时区叫做西五区,西五区表示为:GMT-05。

如下图区域划分:

在这里插入图片描述

2.3. UTC

UTC即:世界协调时(Universal Time Coordinated的缩写)

以原子时钟长为基础,比GMT格林威治时更加科学更加精确。

UTC是国际无线电咨询委员会制定和推荐的,若与GMT时差大于0.9秒,则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。

中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。

注意事项:

  1. 目前UTC与GMT 相差为0.9秒,故二者可以基本视为一致。
    我们一般认为GMT和UTC是一样的,都与英国伦敦的本地时相同。
  2. 早期的XP系统中,默认时间格式是GMT。而到了Win7之后,默认时间格式已经改成了UTC
  3. 阿里云API接口编程中,全部都是UTC

2.4. CST

这个代号缩写,并不是一个统一标准,目前,可以同时代表如下 4 个不同版本的时区概念(要根据上下文语义加以区分):

  1. China Standard Time 中国标准时区 (UTC+8)
  2. Cuba Standard Time 古巴标准时区 (UTC-4)
  3. Central Standard Time (USA) 美国中央时区 (UTC-6)
  4. Central Standard Time (Australia) 澳大利亚中央时区(UTC+9)

2.5. UNIX时间戳(timestamp)

计算机中的UNIX时间戳,是以GMT/UTC时间「1970-01-01T00:00:00」为起点,到当前具体时间的秒数(不考虑闰秒)。这样做的目的,主要是通过“整数计算”来简化计算机对时间操作的复杂度。

无论何种编程语言,基本都有获取unix时间戳的系统方法。

注意事项:

  1. 如果开发的软件系统仅仅在国内用,用timestamp没有太大问题(因为大家的linux服务器的时区是一样的)
  2. 如果软件系统需要跨国服务,则必须用UTC(比如阿里云API),否则就会因为服务器的UTC时区不同,导致timestamp结果值混乱

2.6. 获取其他时区的时间

  1. GMT-5:00:纽约时间
  2. GMT+8:00:北京时间
public static String getChinaTime() {    TimeZone timeZone = TimeZone.getTimeZone("GMT-5:00");    SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    simpleDateFormat.setTimeZone(timeZone);    return simpleDateFormat.format(new Date());}

如果涉及到字符串转换日期类型的,可以考虑使用hutoo当中的DateUtil.parse();

三、传参格式化

3.1. Json传参格式化

添加@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

@TableField(value = "upload_date")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date uploadDate;

测试一:设置的yyyy-MM-dd HH:mm:ss传的yyyy-MM-dd 直接400

测试二:传yyyy-MM-dd HH:mm:ss,通过这里可以发现,前端传什么日期和时间,后端就会收到什么,而且返回给前端的也没有时间转换。其实我们开发当中很多时候要的就是这样的效果,前端传什么后端就反什么!不能因为经过了一圈后端接口,时间格式就给变了!

但是问题来了,控制台打印的是:Fri Sep 16 20:11:11 CST 2022,显然是存在问题的,明明是传的2022-09-16 12:11:11,会发现他的时间上加了8个小时,并且数据库当中也是存的加了8个小时,那也就是@JsonFormat在格式化的时候,以为前端传的是世界时间,这该怎么办呢?

告诉@JsonFormat接数据的格式是GMT+8,而不是UTC时间,不需要加8个小时!,加上之后再进行测试,会发现前端传什么后端通过System.out.println(student.getUploadDate());就会输出什么。并且存储到数据库当中也是!

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

3.2. url传参格式化

添加@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")

@TableField(value = "upload_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date uploadDate;

加上之后会发现如下:传参是不报错了,但是返回的是iso格式!并且是+00:00代表的是世界时间!

添加@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")

@TableField(value = "upload_date")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")private Date uploadDate;

四、注解

可以这么用:

@GetMapping("/getByCreateDate")public Date getByCreateDate(@RequestParam("createDate")@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") Date createDate) {    System.out.println(createDate);    return createDate;}

4.1. @DateTimeFormat 其他属性

@DateTimeFormat注解除了pattern自定义格式外,还有iso属性。可以指定格式!

用法: @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
前端传参格式:2021-11-26T06:07:15.870Z,一旦不是这种格式直接400错误!

用法:@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
前端传参格式:2021-11-26T06:07:15.870Z,可以不带时分秒,也可以带时分秒,也可以不带,但是必须是ISO格式!

4.2. @JsonFormat 其他属性

它只会格式化返回类型和传参类型为json时的日期类型,比如使用@ResponseBody返回json数据的时候,和@RequestBody接入的参数!

@JsonFormat有以下几个属性:

  • pattern: 表示日期的格式
  • timezone: 默认是GMT,中国需要GMT+8
  • locale: 根据位置序列化的一种格式
  • shap: 表示序列化后的一种类型。

五、springboot全局时间格式化

如下配置相当于设置了全局的@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8"),注解配置要优先于全局配置!

spring:  jackson:  # 格式化全局时间字段    date-format: yyyy-MM-dd HH:mm:ss  # 指定时间区域类型      time-zone: GMT+8

假如配置了以上配置接口返回的日期数据为时间戳:这时候看看进行web配置是否是继承WebMvcConfigurationSupport这个类,如果有选择去实现WebMvcConfigurer这个接口,那么springboot的mvc自动配置则不会受影响。

如下配置相当于设置了全局的@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss"),注解配置要优先于全局配置!

spring:  mvc:    format:#      默认的格式是dd/MM/yyyy,除此外任何格式都会400异常      date: yyyy-MM-dd HH:mm:ss

来源地址:https://blog.csdn.net/weixin_43888891/article/details/126846791

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

@DateTimeFormat 和 @JsonFormat 注解详解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Java中@DateTimeFormat和@JsonFormat注解介绍

@DateTimeFormat和@JsonFormat都是处理时间格式化问题的,把其他类型转换成自己需要的时间类型,下面这篇文章主要给大家介绍了关于Java中@DateTimeFormat和@JsonFormat注解介绍的相关资料,需要的朋友可以参考下
2022-11-13

Java中注解@JsonFormat的用法详解

这篇文章主要给大家介绍了关于Java中注解@JsonFormat用法的相关资料,以及分享了@JsonFormat将枚举序列化为对象的方法,文中给出了详细的代码实例,需要的朋友可以参考下
2023-01-06

springboot2中使用@JsonFormat注解不生效怎么解决

这篇“springboot2中使用@JsonFormat注解不生效怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“sp
2023-06-29

详解Spring注解--@Autowired、@Resource和@Service

什么是注解传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop、事物,这么做有两个缺点:1、如果所有的内容都配置在.xml文件中,那么.xml文件将会十分庞大;如果按需求分开.xml文件,那么.xml文件又会非常多。
2023-05-31

EasyExcel格式化映射注解和样式注解详解

一、概述 使用注解很简单,只要在对应的实体类上面加上注解即可。 也就是说使用实体类模型来读写Excel文件时,可以通过注解来控制实体类字段和Excel列之间的对应关系。 二、ExcelProperty 2.1 作用 ExcelPropert
2023-08-21

Spring注解@Configuration和@Component区别详解

@Component和@Configuration都可以作为配置类,之前一直都没觉得这两个用起来有什么差别,可能有时程序跑的和自己想的有所区别也没注意到,下面这篇文章主要给大家介绍了关于Spring注解@Configuration和@Component区别的相关资料,需要的朋友可以参考下
2023-05-14

@Profile注解详解

@Profile:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;开发环境develop、测试环境test、生产环境master数据源:(/dev) (/test) (/master)@Profile:指定组件在哪个环境的情况下才能
@Profile注解详解
2018-01-19

Spring注解详解

概述 注释配置相对于 XML 配置具有很多的优势:它可以充分利用 Java 的反射机制获取类结构信息,这些信息可以有效减少配置的工作。如使用 JPA 注释配置 ORM 映射时,我们就不需要指定 PO 的属性名、类型等信息,如果关系表字段和
2023-06-03

Java注解详解

目录 一、发现注解二、注解是什么1. 注解的本质2. 注解是针对Java编译器的说明 三、为什么要使用注解四、Java中常用的注解4.1 基础注解(spring-context、spring-we
2023-08-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录