SpringBoot中时间格式化的5种方法!
在我们日常工作中,时间格式化是一件经常遇到的事儿,所以本文我们就来盘点一下 Spring Boot 中时间格式化的几种方法。
时间问题演示
为了方便演示,我写了一个简单 Spring Boot 项目,其中数据库中包含了一张 userinfo 表,它的组成结构和数据信息如下:
项目目录是这样的:
UserController 实现代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private UserMapper userMapper;
@RequestMapping("/list")
public List<UserInfo> getList() {
return userMapper.getList();
}
}
UserMapper 实现代码如下:
@Mapper
public interface UserMapper {
public List<UserInfo> getList();
}
UserInfo 实现代码如下:
@Data
public class UserInfo {
private int id;
private String username;
private Date createtime;
private Date updatetime;
}
UserMapper.xml 实现代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.UserMapper">
<select id="getList" resultType="com.example.demo.model.UserInfo">
select * from userinfo
</select>
</mapper>
经过以上内容的编写,我们就制作出了一个简单的 Spring Boot 项目了。接下来,我们使用 PostMan 来模拟调用 UserController 接口,执行结果如下:
从上述结果可以看出,时间字段 createtime
和 updatetime
的显示方式是很“凌乱”的,并不符合我们的阅读习惯,也不能直接展示给前端的用户使用,这时候,我们就需要对时间进行格式化处理了。
时间格式化的方法总共包含以下 5 种。
1.前端时间格式化
如果后端在公司中拥有绝对的话语权,或者是后端比较强势的情况下,我们可以将时间格式化的这个“锅”强行甩给前端来处理。
为了让这个“锅”甩的更平顺一些(磊哥不做厨师都可惜了),咱们可以给前端工程师提供切实可行的时间格式化方法,实现代码如下。
JS 版时间格式化
function dateFormat(fmt, date) {
let ret;
const opt = {
"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() // 秒
// 有其他格式化字符需求可以继续添加,必须转化成字符串
};
for (let k in opt) {
ret = new RegExp("(" + k + ")").exec(fmt);
if (ret) {
fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
};
};
return fmt;
}
方法调用:
let date = new Date();
dateFormat("YYYY-mm-dd HH:MM:SS", date);
>>> 2021-07-25 21:45:12
2.SimpleDateFormat格式化
大多数情况下,我们还是需要自力更生,各扫门前雪的,这个时候我们后端程序员就需要发挥自己的特长了,我们提供的第 1 个时间格式化的方法是使用 SimpleDateFormat
来进行时间格式化,它也是 JDK 8 之前重要的时间格式化方法,它的核心实现代码如下:
// 定义时间格式化对象和定义格式化样式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化时间对象
String date = dateFormat.format(new Date())
接下来我们使用 SimpleDateFormat
来实现一下本项目中的时间格式化,它的实现代码如下:
@RequestMapping("/list")
public List<UserInfo> getList() {
// 定义时间格式化对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
List<UserInfo> list = userMapper.getList();
// 循环执行时间格式化
list.forEach(item -> {
// 使用预留字段 ctime 接收 createtime 格式化的时间(Date->String)
item.setCtime(dateFormat.format(item.getCreatetime()));
item.setUtime(dateFormat.format(item.getUpdatetime()));
});
return list;
}
程序执行结果如下:
从上述结果可以看出,时间格式化没有任何问题,以及到底我们预想的目的了。但细心的读者会发现,为什么接口的返回字段咋变了呢?(之前的字段是 createtime
现在却是 ctime
...)
这是因为使用 #SimpleDateFormat.format
方法之后,它返回的是一个 String
类型的结果,而我们之前的 createtime
和 updatetime
字段都是 Date
类型的,因此它们是不能接收时间格式化得结果的。
所以此时我们就需要在实体类 UserInfo
新增两个字符串类型的“时间”字段,再将之前 Data
类型的时间字段进行隐藏,最终实体类 UserInfo 的实现代码如下:
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private int id;
private String username;
@JsonIgnore // 输出结果时隐藏此字段
private Date createtime;
// 时间格式化后的字段
private String ctime;
@JsonIgnore // 输出结果时隐藏此字段
private Date updatetime;
// 时间格式化后的字段
private String utime;
}
我们可以使用 @JsonIgnore
注解将字段进行隐藏,隐藏之后的执行结果如下:
3.DateTimeFormatter格式化
JDK 8 之后,我们可以使用 DateTimeFormatter
来替代 SimpleDateFormat
,因为 SimpleDateFormat
是非线程安全的,而 DateTimeFormatter
是线程安全的,所以如果是 JDK 8 以上的项目,尽量使用 DateTimeFormatter
来进行时间格式化。
DateTimeFormatter
格式化的代码和 SimpleDateFormat
类似,具体实现如下:
@RequestMapping("/list")
public List<UserInfo> getList() {
// 定义时间格式化对象
DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
List<UserInfo> list = userMapper.getList();
// 循环执行时间格式化
list.forEach(item -> {
// 使用预留字段 ctime 接收 createtime 格式化的时间(Date->String)
item.setCtime(dateFormat.format(item.getCreatetime()));
item.setUtime(dateFormat.format(item.getUpdatetime()));
});
return list;
}
执行结果如下所示:
DateTimeFormatter
和 SimpleDateFormat
在使用上的区别是 DateTimeFormatter
是用来格式化 JDK 8 提供的时间类型得,如 LocalDateTime
,而 SimpleDateFormat
是用来格式化 Date
类型的,所以我们需要对 UserInfoer 实体类做如下的修改:
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class UserInfo {
private int id;
private String username;
@JsonIgnore
private LocalDateTime createtime;
private String ctime;
@JsonIgnore
private LocalDateTime updatetime;
private String utime;
}
我们可以使用 LocalDateTime
来接收 MySQL 中的 datetime
类型。
4.全局时间格式化
以上两种后端格式化的实现都有一个致命的缺点,它们在进行时间格式化的时候,都需要对核心业务类做一定的修改,这就相当为了解决一个问题,又引入了一个新的问题,那有没有简单一点、优雅一点的解决方案呢?
答案是:有的。我们可以不改任何代码,只需要在配置文件中设置一下就可以实现时间格式化的功能了。
首先,我们找到 Spring Boot 的配置文件 application.properties(或 application.yml),只需要在 application.properties 配置文件中添加以下两行配置:
# 格式化全局时间字段
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# 指定时间区域类型
spring.jackson.time-zone=GMT+8
这样设置之后,我们将原始的 UserInfo 和 UserController 进行还原。
UserInfo 实现代码如下:
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private int id;
private String username;
private Date createtime;
private Date updatetime;
}
UserController 实现代码:
@RequestMapping("/list")
public List<UserInfo> getList() {
return userMapper.getList();
}
然后我们运行程序,看到的执行结果如下:
从以上结果和代码可以看出,我们只需要在程序中简单配置一下,就可以实现所有时间字段的格式化了。
实现原理分析
为什么在配置文件中设置一下,就可以实现所有时间字段的格式化了呢?
# 格式化全局时间字段
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# 指定时间区域类型
spring.jackson.time-zone=GMT+8
这是因为 Controller 在返回数据时,会自动调用 Spring Boot 框架中内置的 JSON 框架 Jackson,对返回的数据进行统一的 JSON 格式化处理,在处理的过程中它会判断配置文件中是否设置了“spring.jackson.date-format=yyyy-MM-dd HH:mm:ss”,如果设置了,那么 Jackson 框架在对时间类型的字段输出时就会执行时间格式化的处理,这样我们就通过配置来实现全局时间字段的格式化功能了。
为什么要指定时间区域类型“spring.jackson.time-zone=GMT+8”呢?
最现实的原因是,如果我们不指定时间区域类型,那么查询出来的时间就会比预期的时间少 8 个小时,这因为我们(中国)所处的时间区域比世界时间少 8 个小时导致的,而当我们设置了时区之后,我们的时间查询才会和预期时间保持一致。
GMT 是什么?
时间区域设置中的“GMT” 是什么意思?
Greenwich Mean Time (GMT) 格林尼治时间,也叫做世界时间。
格林尼治时间
格林尼治是英国伦敦南郊原皇家格林尼治天文台所在地,地球本初子午线的标界处,世界计算时间和经度的起点。以其海事历史、作为本初子午线的标准点、以及格林尼治时间以其命名而闻名于世。这里地势险要,风景秀丽,兼具历史和地方风情,也是伦敦在泰晤士河的东方门户。
不光是天文学家使用格林尼治时间,就是在新闻报刊上也经常出现这个名词。我们知道各地都有各地的地方时间。如果对国际上某一重大事情,用地方时间来记录,就会感到复杂不便.而且将来日子一长容易搞错。因此,天文学家就提出一个大家都能接受且又方便的记录方法,那就是以格林尼治的地方时间为标准。
以本初子午线的平子夜起算的平太阳时。又称格林尼治平时或格林尼治时间。各地的地方平时与世界时之差等于该地的地理经度。1960年以前曾作为基本时间计量系统被广泛应用。由于地球自转速率曾被认为是均匀的,因此在1960年以前,世界时被认为是一种均匀时。由于地球自转速度变化的影响,它不是一种均匀的时间系统,它与原子时或力学时都没有任何理论上的关系,只有通过观测才能对它们进行比较。后来世界时先后被历书时和原子时所取代,但在日常生活、天文导航、大地测量和宇宙飞行等方面仍属必需;同时,世界时反映地球自转速率的变化,是地球自转参数之一,仍为天文学和地球物理学的基本资料。
5.部分时间格式化
某些场景下,我们不需要对全局的时间都进行统一的处理,这种情况我们可以使用注解的方式来实现部分时间字段的格式化。
我们需要在实体类 UserInfo 中添加 @JsonFormat
注解,这样就可以实现时间的格式化功能了,实现代码如下:
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
private int id;
private String username;
// 对 createtime 字段进行格式化处理
@JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss", timezone = "GMT+8")
private Date createtime;
private Date updatetime;
}
修改完代码之后,我们运行项目执行结果如下:
从上述结果可以看出,使用注解的方式也可以实现时间的格式化。它的实现原理和第 4 种时间格式化的实现原理类似,都是在返回数据之前,对相应的字段进行时间格式化的处理。
总结
本文我们介绍了 5 种时间格式化的实现方法,其中第 1 种为前端时间格式化的方法,后 4 种为后端格式化的方法,SimpleDateFormat
和 DateTimeFormatter
格式化的方法更适用普通的 Java 项目,其中 SimpleDateFormat
是非线程安全的,而 DateTimeFormatter
是线程安全的,但它们都不是 Spring Boot 项目中最优的时间格式化方案。
如果是 Spring Boot 的项目,推荐使用第 4 种全局时间格式化或第 5 种局部时间格式化的方式,这两种实现方式都无需修改核心业务代码,只需要简单的配置一下,就可以完成时间的格式化功能了。
参考 & 鸣谢
www.jianshu.com/p/49fb78bca621
baike.baidu.com/item/世界时/692237
关注公号「Java中文社群」查看更多有意思、涨知识的 SpringBoot 文章。
SpringBoot中时间格式化的5种方法!的更多相关文章
- js 中时间格式化的几种方法
1.项目中时间返回值,很过时候为毫秒值,我们需要转换成 能够看懂的时间的格式: 例如: yyyy-MM-dd HH:mm:ss 2.处理方法(处理方法有多种,可以传值到前端处理,也可以后台可以好之后再 ...
- 【转】Asp.net中时间格式化的6种方法详细总结
1. 数据控件绑定时格式化日期方法: 代码如下: <asp:BoundColumn DataField="AddTime" HeaderText="添加时间&quo ...
- Asp.net中时间格式化的几种方法
1. 数据控件绑定时格式化日期方法:<asp:BoundColumn DataField="AddTime" HeaderText="添加时间" Data ...
- python中字符串格式化的两种方法
知识点汇总;1-字符串格式化输出方法一: % 1-print('名字是 %s,年龄是%s' % (name ,age)) 2- %s ---字符串-----相当于执行了str() 3- (name , ...
- python中字符串格式化的四种方法
name = "huangemiling" age= 10 address = 'nanjing' print("My name is %s,age is %d,I co ...
- java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
转载地址:http://www.devba.com/index.php/archives/4581.html java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明); ...
- (转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)
java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date ...
- SpringBoot接收前端参数的三种方法
都是以前的笔记了,有时间就整理出来了,SpringBoot接收前端参数的三种方法,首先第一种代码: @RestController public class ControllerTest { //访问 ...
- C#中实现并发的几种方法的性能测试
C#中实现并发的几种方法的性能测试 0x00 起因 去年写的一个程序因为需要在局域网发送消息支持一些命令和简单数据的传输,所以写了一个C/S的通信模块.当时的做法很简单,服务端等待链接,有用户接入后开 ...
随机推荐
- Json文件解析(上)
Json文件解析(上) 代码地址:https://github.com/nlohmann/json 自述文件 alt=GitHub赞助商 data-canonical-src="https: ...
- Waymo object detect 2D解决方案论文拓展
FixMatch 半监督中的基础论文,自监督和模型一致性的代表作. Consistency regularization: 无监督学习的方式,数据\(A\)和经过数据增强的\(A\)计做\(A'\) ...
- [Django REST framework - 序列化组件、source、钩子函数]
[Django REST framework - 序列化组件.source.钩子函数] 序列化器-Serializer 什么是rest_framework序列化? 在写前后端不分离的项目时: 我们有f ...
- ceph-csi源码分析(8)-cephfs driver分析
更多 ceph-csi 其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 ceph-csi源码分析(8)-cephfs driver分析 当ceph-csi组件启动 ...
- Python UI自动化
Python3--Uiautomator2--Pytest--Alure使用 官方源码GitHub地址:https://github.com/openatx/uiautomator2 介绍 uiaut ...
- OpenGL ES 压缩纹理
什么是压缩纹理 在实际应用特别是游戏中纹理占用了相当大的包体积,而且GPU无法直接解码目前流行的图片格式,图片必须转换为RGB等类型的格式才能上传到GPU内存,这显然增加了GPU内存的占用.为了处理这 ...
- Linux系统安装-C7
1.安装部署操作系统 (1)创建虚拟机,加载系统镜像 (2)进入系统引导界面进行配置 补充:centos7系统网卡名称 默认系统的网卡名称为 eth0 eth1 –centos6 默认系统的网卡名称为 ...
- zabbix_manage的使用
实验环境: zabbix server 172.16.1.121 访问端 172.16.1.122 55.1 说明 zabbix_manager是zabbix终端管理工具,可以在linux终端实现管理 ...
- 面试系列——Mysql索引
1.索引分类 Hash索引Hash 索引查询效率很高,时间复杂度O(1).Mysql Innodb引擎不支持hash索引的.Hash索引适合精确查找,不适合范围查找. 平衡二叉树时间复杂度为 O(n) ...
- CRM系统对企业管理的作用有多大?
随着市场经济的发展,对任何行业的企业来说,客户都是非常重要的一个部分.CRM系统帮助企业做到以客户为中心,它可以根据客户的具体要求进行跟进和反馈,在很大程度上提高公司的客户服务水平和客户满意度,进而提 ...