赞
踩
这一篇文章足以让你对Java当中Date时间上的理解更上一层楼,本篇文章主要通过代码的形式来进行试验,彻彻底底搞明白日期传参,以及日期返回参数的格式相关问题,每一个步骤都会记得特别详细!
本篇文章主要针对以下三点,来进行代码试验:
如果想要看详细测试过程的,可以看下面的每一步骤,如果着急要结果的,看总结足矣!
@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.annotation | com.fasterxml.jackson.annotation |
注意:
yyyy-MM-dd
格式,如果传时分秒就会报错,或者是使用 yyyy-MM-dd HH:mm:ss
,如果传yyyy-MM-dd
也会报错。首先准备一张表:时间我使用的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") @RestController public 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
测试一:通过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参数类型错误!
不使用任何注解的时候,总结如下:
yyyy-MM-dd
格式,假如传yyyy-MM-dd HH:mm:ss
或者yyyy/MM/dd
是都会报400错误的!DATETIME
类型,前端传的是yyyy-MM-dd
格式 这时候数据库当中会自动补齐时分秒 yyyy-MM-dd 08:00:00
。yyyy-MM-dd 08:00:00
;2022-09-15T14:40:50.000+00:00
(世界时的IOS的格式),当我们使用System.out.println(new Date());
单独输出日期,格式是:Thu Sep 15 23:24:01 CST 2022
,会发现两个压根不是一个东西。2022-09-15 22:40:50
,反给前端的是2022-09-15T14:40:50.000+00:00
,这个格式是ios时间格式,也就是在不使用注解的情况,反给前端的时候使用的是世界时IOS格式。世界UTC时间和中国时间有八个小时的时差!测试一:传yyyy-MM-dd
或者传 yyyy-MM-dd HH:mm:ss
都会报400错误!
想要搞明白日期格式化问题,首先要明白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()));
国际标准ISO 8601,是国际标准化组织的日期和时间的表示方法,2022-09-15T14:40:50.000+00:00
就是典型的ISO格式,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》。
ISO 8601日期格式如下:YYYY-MM-DDThh:mm:ss[.mmm]TZD
2022-09-15T14:40:50.000+00:00
,中国时间和世界时间相差8个小时,假如中国时间就是2022-09-15T14:40:50.000+08:00
它是世界时
又叫格林尼治标准时间
(格林尼治所在地的标准时间);格林尼治在英国伦敦
,那里有一条非常著名的线,叫本初子午线
;世界计算时间的起点(时区的划分)以及经度的起点就是这条线。
格林尼治(Greenwich),是英国伦敦的一个区,位于伦敦东南、泰晤士河南岸。
地球分为
24 个时区
,一个时区的范围是十五个经度,地球又分东西半球,东西半球各占十二个时区
;每个时区相差一个小时,最多相差24小时,也就是一天。凡向西走,每过一个时区,时间要慢一个小时,就要把表拨慢1小时(就是说你所在的位置是两点,向西一个时区就减去一个小时,也就是一点);凡向东走,每过一个时区,时间要快一个小时,就要把表拨快1小时(比如1点拨到2点)。格林尼治天文台所在的地方叫零时区。零时区表示为GMT+00,零时区缩写叫z
。
以格林尼治天文台所在的时区为中心(GMT+00),向东为正,向西为负
;零时区比东时区晚,比西时区早。0时区比东八区的时间晚8小时,比西五区的时间早5小时。美国华盛顿比北京慢13小时;
在中国以北京所在的区统一时间,北京所在的时区叫东八区
,东八区表示形式是:GMT+08;
美国常用美东时间来表示,美东时间表示纽约、华盛顿所在的时区,那个时区叫做西五区
,西五区表示为:GMT-05。
如下图区域划分:
UTC即:世界协调时(Universal Time Coordinated的缩写)
以原子时钟长为基础,比GMT格林威治时更加科学更加精确。
UTC是国际无线电咨询委员会制定和推荐的
,若与GMT时差大于0.9秒,则由位于巴黎的国际地球自转事务中央局发布闰秒,使UTC与地球自转周期一致。
中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。
注意事项:
这个代号缩写,并不是一个统一标准,目前,可以同时代表如下 4 个不同版本的时区概念(要根据上下文语义加以区分):
计算机中的UNIX时间戳,是以GMT/UTC时间「1970-01-01T00:00:00」为起点
,到当前具体时间的秒数(不考虑闰秒)。这样做的目的,主要是通过“整数计算”来简化计算机对时间操作的复杂度。
无论何种编程语言,基本都有获取unix时间戳的系统方法。
注意事项:
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();
添加@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")
添加@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;
}
@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格式!
它只会格式化返回类型和传参类型为json时的日期类型,比如使用@ResponseBody返回json数据的时候,和@RequestBody接入的参数!
@JsonFormat有以下几个属性:
如下配置相当于设置了全局的@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
在Spring Boot中,如果你使用了WebMvcConfigurationSupport,那么Spring Boot的自动配置将会失效,因为WebMvcConfigurationSupport是一个完全替代默认配置的配置类。使用这个类可能导致Spring Boot MVC的一些默认配置失效,包括Jackson的默认配置。
推荐的方式是使用WebMvcConfigurer接口,而不是继承WebMvcConfigurationSupport。WebMvcConfigurer接口提供了一种更灵活的方式来定制Spring MVC的配置,而不会完全取代默认配置。
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
converter.setObjectMapper(objectMapper);
converters.add(converter);
}
}
如下配置相当于设置了全局的@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
,注解配置要优先于全局配置!
spring:
mvc:
format:
# 默认的格式是dd/MM/yyyy,除此外任何格式都会400异常
date: yyyy-MM-dd HH:mm:ss
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。