作者|王磊来源|Java中文社区(ID:javacn666)转载请联系授权(微信ID:GG_Stone)。在我们的日常工作中,时间格式化是很常见的事情,那么在这篇文章中我们就来看看SpringBoot中时间格式化的几种方法。时间问题的演示为了演示方便,我写了一个简单的SpringBoot工程,里面包含了数据库中的userinfo表。其组成结构和数据信息如下:项目目录如下:UserController实现代码如下:@RestController@RequestMapping("/user")publicclassUserController{@ResourceprivateUserMapperuserMapper;@RequestMapping("/list")publicListgetList(){returnuserMapper.getList();}}UserMapper实现代码如下:@MapperpublicinterfaceUserMapper{publicListgetList();}UserInfo实现代码如下:@DatapublicclassUserInfo{privateintid;privateStringusername;privateDatecreatetime;privateDateupdatetime;}UserMapper.xml实现代码如下:select*fromuserinfo写完上面的内容,我们就创建创建了一个简单的SpringBoot项目。接下来我们使用PostMan模拟调用UserController接口。执行结果如下:从上面的结果我们可以看出时间字段createtime和updatetime的显示方式很“乱”,不符合我们的要求。阅读习惯,不能直接展示给前端用户。这时候,我们就需要对时间进行格式化。时间格式化一共有5种方法。1、前端时间格式化如果后端在公司有绝对的话语权,或者后端比较强大,我们可以强行把时间格式化这“锅”扔给前端处理。为了让这个“锅”倒得更顺利(可惜雷哥不当厨师),我们可以给前端工程师提供一个可行的时间格式化方法,实现代码如下。JS版本时间格式化函数dateFormat(fmt,date){letret;constopt={"Y+":date.getFullYear().toString(),//年份"m+":(date.getMonth()+1).toString(),//月"d+":date.getDate().toString(),//日"H+":date.getHours().toString(),//小时"M+":date.getMinutes().toString(),//分"S+":date.getSeconds().toString()//seconds//可以加其他格式化字符,必须转成字符串};for(letkinopt){ret=newRegExp("("+k+")").exec(fmt);if(ret){fmt=fmt.replace(ret[1],(ret[1].length==1)?(opt[k]):(opt[k].padStart(ret[1].length,"0")))};};returnfmt;}方法调用:letdate=newDate();dateFormat("YYYY-mm-ddHH:MM:SS",date);>>>2021-07-2521:45:122.SimpleDateFormat格式化大多数情况下,我们还是需要自力更生,擦干净门。这时候我们后端程序员就需要发挥自己的优势了,我们提供的第一个时间格式化方法就是使用SimpleDateFormat进行时间格式化。也是JDK8之前重要的时间格式化方法,其核心实现代码如下://定义时间格式化对象和定义格式化样式SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//Format时间对象Stringdate=dateFormat.format(newDate())样式SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");//格式化时间对象Stringdate=dateFormat.format(newDate())接下来我们使用SimpleDateFormat来实现本项目中的功能Time格式化,其实现代码如下:@RequestMapping("/list")publicListgetList(){//定义时间格式化对象SimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");Listlist=userMapper.getList();//循环执行时间格式化list.forEach(item->{//使用保留字段ctime接收createtime(Date->String)格式化的时间item.setCtime(dateFormat.format(item.getCreatetime()));item.setUtime(dateFormat.format(item.getUpdatetime()));});returnlist;}程序执行结果如下:从上面的结果可以看到时间格式没有任何问题,也是我们预期的目的,但是细心的读者会发现,为什么接口的返回字段变了?(之前的字段是createtime,现在是ctime。。。)这是因为#SimpleDateFormat.format方法之后返回的是String类型的结果,而我们之前的createtime和updatetime字段都是Date类型的,所以它们无法接收时间格式的结果。所以这时候我们需要在实体类UserInfo中增加两个字符串类型的“时间”字段,然后隐藏之前的Data类型的时间字段。实体类UserInfo最终实现代码如下:importcom.fasterxml.jackson.annotation.JsonIgnore;importlombok.Data;importjava.util.Date;@DatapublicclassUserInfo{privateintid;privateStringusername;@JsonIgnore//输出结果时隐藏该字段privateDatecreatetime;//时间格式化后的字段privateStringctime;@JsonIgnore//输出结果时隐藏该字段privateDateupdatetime;//时间格式化字段privateStringutime;}我们可以使用@JsonIgnore注解隐藏该字段,隐藏后的执行结果为如下:3.DateTimeFormatter格式化JDK8后,我们可以用DateTimeFormatter代替SimpleDateFormat,因为SimpleDateFormat不是线程安全的,而DateTimeFormatter是线程安全的,所以如果是JDK8以上的项目,时间尽量用DateTimeFormatter格式化。DateTimeFormatter格式化代码类似于SimpleDateFormat,具体实现如下:@RequestMapping("/list")publicListgetList(){//定义时间格式对象DateTimeFormatterdateFormat=DateTimeFormatter.ofPattern("yyyy-MM-ddHH:mm:ss");Listlist=userMapper.getList();//循环执行时间格式化list.forEach(item->{//使用保留字段ctime接收createtime格式化的时间(Date->String)item.setCtime(dateFormat.format(item.getCreatetime()));item.setUtime(dateFormat.format(item.getUpdatetime()));});returnlist;}执行结果如下:DateTimeFormatter和SimpleDateFormat在使用上的区别是DateTimeFormatter是用来格式化JDK8提供的时间类型,比如LocalDateTime,而SimpleDateFormat是用来格式化Date类型的,所以我们需要对UserInfoer实体类做如下修改:导入com.fasterxml.jackson。annotation.JsonIgnore;importlombok.Data;importjava.time.LocalDateTime;@DatapublicclassUserInfo{privateintid;privateStringusername;@JsonIgnoreprivateLocalDateTimecreatetime;privateStringctime;@JsonIgnoreprivateLocalDateTimeupdatetime;privateStringutime;}我们可以使用LocalDateTime接收MySQL中的datetime类型4.全局时间格式化以上两种后端格式化实现都有一个致命的缺点。他们在格式化的时候,都需要对核心业务类进行一定的修改,这就相当为了解决一个问题,又引入了一个新的问题。有没有更简单优雅的解决方案?答案是:是的。我们不需要改动任何代码,只需要在配置文件中设置即可实现时间格式化功能。首先,我们找到SpringBoot的配置文件application.properties(或application.yml)。我们只需要在application.properties配置文件中加入如下两行配置即可:#格式化全局时间字段spring.jackson.date-format=yyyy-MM-ddHH:mm:ss#指定时区类型spring。jackson.time-zone=GMT+8这样设置后,我们将恢复原来的UserInfo和UserController。UserInfo实现代码如下:importlombok.Data;importjava.util.Date;@DatapublicclassUserInfo{privateintid;privateStringusername;privateDatecreatetime;privateDateupdatetime;}UserController实现代码:@RequestMapping("/list")publicListgetList(){returnuserMapper.getList();}然后我们运行程序,看到的执行结果如下:从上面的结果和代码可以看出,我们只需要在程序中简单配置一下,就可以实现所有时间的格式化领域。实现原理分析为什么所有时间字段的格式化都可以通过在配置文件中设置来实现呢?#格式化全球时间字段spring.jackson.date-format=yyyy-MM-ddHH:mm:ss#指定时区输入spring.jackson.time-zone=GMT+8。这是因为Controller在返回数据的时候,会自动调用SpringBoot框架中内置的JSON框架Jackson,对返回的数据进行统一的JSON格式化。在处理过程中,会判断配置文件中是否设置了“spring.jackson.date-format=yyyy-MM-ddHH:mm:ss”。如果设置了,Jackson框架在输出时间类型字段的时候会执行格式化处理,这样我们就可以通过配置实现全局时间字段的格式化功能。为什么要指定时区类型“spring.jackson.time-zone=GMT+8”?最现实的原因是,如果我们不指定时区类型,查询时间会比预期时间少8小时,这是因为我们(中国)所在的时区比世界时间少8小时,而当我们设置了时区后,我们的时间查询就会和期望的时间保持一致。什么是格林威治标准时间?“GMT”在时区设置中是什么意思?GreenwichMeanTime(GMT)格林威治标准时间,又称世界时间。格林威治标准时间格林威治标准时间是原英国伦敦南郊皇家格林威治天文台的所在地,是地球本初子午线的标示地,也是世界上计算时间和经度的起点。以其航海历史而闻名,作为本初子午线的标准点,格林威治标准时间就是以此命名的。这里地势险要,风景优美,既有历史,又有风土人情。它也是泰晤士河畔伦敦的东部门户。不仅天文学家使用格林威治标准时间,新闻中也经常使用该术语。我们知道到处都有当地时间。如果用当地时间来记录世界上的重要事件,会很复杂和不方便,而且以后很容易出错。因此,天文学家提出了一种方便且为大家所接受的记录方式,那就是以格林威治标准当地时间为标准。从本初子午线的平均午夜算起的平均太阳时。也称为格林威治标准时间或格林威治标准时间。正常时间和世界标准时间之间的差异等于该地点的地理经度。1960年以前作为基本时间测量系统被广泛使用。由于地球自转速度一度被认为是匀速的,所以1960年以前世界时被认为是统一时间。由于地球自转速度变化的影响,它不是一个统一的时间。统一时间系统,与原子时、机械时没有理论关系,只能通过观察来比较。后来,世界时先后被历书时和原子时所取代,但在日常生活、天文导航、大地测量和航天飞行中仍然必不可少。同时,世界时反映了地球自转速率的变化,是地球自转参数之一。仍然是天文学和地球物理学的基础数据。5.部分时间格式化在某些场景下,我们不需要对全局时间进行统一处理。这种情况下,我们可以使用注解来实现部分时间字段的格式化。我们需要在实体类UserInfo中添加@JsonFormat注解,这样才能实现时间格式化功能。实现代码如下:importcom.fasterxml.jackson.annotation.JsonFormat;importlombok.Data;importjava.util.Date;@DatapublicclassUserInfo{privateintid;privateStringusername;//格式化createtime字段@JsonFormat(pattern="yyyy-MM-ddhh:mm:ss",timezone="GMT+8")privateDatecreatetime;privateDateupdatetime;}修改代码后,我们运行项目执行结果如下:从上面的结果可以看出时间格式化也可以通过使用注释来实现。它的实现原理和第四种时间格式的实现原理类似,都是在返回数据前对相应的字段进行时间格式处理。总结在本文中,我们介绍了时间格式化的五种实现方式,第一种是前端时间格式化方式,后四种是后端格式化方式。SimpleDateFormat和DateTimeFormatter格式化方法更适合普通的Java项目,其中SimpleDateFormat不是线程安全的,而DateTimeFormatter是线程安全的,但都不是SpringBoot项目中最优的时间格式化方案。如果是SpringBoot项目,建议使用第四种全局时间格式或者第五种本地时间格式方式。这两种实现方式都不需要修改核心业务代码,只需要简单的配置就可以完成时间格式化功能了。