springboot:时间格式化的5种方法(解决后端传给前端的时间格式转换问题)推荐使用第4和第5种!

news2024/12/24 9:09:36

本文转载自:springboot:时间格式化的5种方法(解决后端传给前端的时间显示不一致)_为什么前端格式化日期了后端还要格式化_洛泞的博客-CSDN博客

时间问题演示

为了方便演示,我写了一个简单 Spring Boot 项目,其中数据库中包含了一张 userinfo 表,它
的组成结构和数据信息如下:

 项目目录是这样的:

 

UserController 实现代码如下: 

@RestController
@RequestMapping("/user")
publicclass 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
publicclass UserInfo {
    privateint 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 版时间格式化

假设您有一个名为`data`的数组,其中包含后端响应的数据,其中包含了`createdTime`字段

"createdTime": { "nano": 0, "year": 2021, "monthValue": 12, "dayOfMonth": 16, "hour": 5, "minute": 54, "second": 45, "dayOfWeek": "THURSDAY", "dayOfYear": 350, "month": "DECEMBER", "chronology": { "id": "ISO", "calendarType": "iso8601" } }

,您可以像这样在el-table中显示它: 

'''vue

<template>
  <div>
    <el-table :data="data">
      <el-table-column label="创建时间">
        <template slot-scope="scope">
          {{ formatDate(scope.row.createdTime) }}
        </template>
      </el-table-column>
      <!-- 其他列 -->
    </el-table>
  </div>
</template>
 
<script>
export default {
  data() {
    return {
      data: [], // 后端响应的数据
    };
  },
  methods: {
    formatDate(timestamp) {
      // 使用JavaScript的Date对象将时间戳格式化为某年-某月-某日 某时:某分:某秒
      const date = new Date(timestamp.year, timestamp.monthValue - 1, timestamp.dayOfMonth, timestamp.hour, timestamp.minute, timestamp.second);
      const year = date.getFullYear();
      const month = (date.getMonth() + 1).toString().padStart(2, '0'); // 补零
      const day = date.getDate().toString().padStart(2, '0');
      const hours = date.getHours().toString().padStart(2, '0');
      const minutes = date.getMinutes().toString().padStart(2, '0');
      const seconds = date.getSeconds().toString().padStart(2, '0');
      
      return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    },
  },
};
</script>

'''

 2.SimpleDateFormat格式化(Date)

使用 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
publicclass UserInfo {
    privateint 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
publicclass UserInfo {
    privateint 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 配置文件中添加以下两行配置:

'''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
publicclass UserInfo {
    privateint id;
    private String username;
    private Date createtime;
    private Date updatetime;
}

UserController 实现代码:

@RequestMapping("/list")
public List<UserInfo> getList() {
    return userMapper.getList();
}

然后我们运行程序,看到的执行结果如下:

从以上结果和代码可以看出,我们只需要在程序中简单配置一下,就可以实现所有时间字段的格式化了。

实现原理分析
为什么在配置文件中设置一下,就可以实现所有时间字段的格式化了呢?

'''properties

# 格式化全局时间字段
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
publicclass UserInfo {
    privateint 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 种局部时间格式化的方式,这两种实现方式都无需修改核心业务代码,只需要简单的配置一下,就可以完成时间的格式化功能了。
————————————————
原文链接:https://blog.csdn.net/qq_41366629/article/details/118972757

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/962887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式-工厂模式Factory

工厂模式 b.工厂方法模式 (Factory Method) (重点)1) 简单工厂 Simple Factory1.a) 简单工厂的好处 2) 工厂方法 Factory Method2.a) 对工厂进行抽象化 (版本一)2.b) 对工厂进行缓存 (版本二)2.c) 加载配置文件到缓存中 (版本三)c.1) 产品线 c.抽象工厂模式 (Abstract Factory)…

五子棋游戏禁手算法的改进

五子棋游戏禁手算法的改进 五子棋最新的禁手规则&#xff1a; 1&#xff0e;黑棋禁手判负、白棋无禁手。黑棋禁手有“三三”&#xff08;包括“四三三”&#xff09;、“四四”&#xff08;包括“四四三”&#xff09;和“长连”。黑棋只能以“四三”取胜。 2&#xff0e;黑方…

B端系统设计之【权限】详解

衡量B端产品系统好坏的一个重要标准就是它的权限是否细致&#xff0c;拓展性是否强。 权限管理是B端产品系统的基础&#xff0c;好的权限管理系统延展性较强&#xff0c;即使业务发生变化也能避免大改和推倒重建。 权限分类 1、功能权限 功能权限是指用户登录系统之后&#xff…

前端面试中Vue的有经典面试题三

11. 网页从输入网址到渲染完成经历了哪些过程&#xff1f; 大致可以分为如下7步&#xff1a; 输入网址&#xff1b; 发送到DNS服务器&#xff0c;并获取域名对应的web服务器对应的ip地址&#xff1b; 与web服务器建立TCP连接&#xff1b; 浏览器向web服务器发送http请求&a…

【自用】西门子s7-200连接显示屏和物联网盒子完整配置过程

总览 1.PLC配置 2.显示屏配置 3.物联网盒子配置 一、PLC配置 1.连接PLC软件 STEP-7MicroWIN V4.0 SP9完整版 链接&#xff1a;https://pan.baidu.com/s/17LMEXnbkQZMPI8Bte24Eug?pwdjsi3 提取码&#xff1a;jsi3 2.PLC配置 打开 PLC 上面的小盖子&#xff0c;把红色按钮…

【代码随想录day23】不同路径 II

题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到…

3.1.6 练习 基于GPA排名计算本专业保研名单

C自学精简教程 目录(必读) GPA概念回顾 平均学分绩点GPA(Grade Point Average)是对一个学生大学学习成绩的综合的衡量指标。 在前面的文章 本科生学分绩点GPA计算 中&#xff0c;我们知道了什么是平均学分绩点GPA&#xff0c;以及如何计算它。 基于GPA给学生排名 现在我们…

介绍几种使用工具

FileWatch&#xff0c;观测文件变化&#xff0c;源码地址&#xff1a;https://github.com/ThomasMonkman/filewatch nlohmann::json&#xff0c;json封装解析&#xff0c;源码地址&#xff1a;https://github.com/nlohmann/json optionparser&#xff0c;解析选项&#xff0c;源…

4.(Python数模)0-1规划

Python解决0-1规划问题 参考下面文章 源代码 import pulp # 导入 pulp 库# 主程序 def main():# 投资决策问题&#xff1a;# 公司现有 5个拟投资项目&#xff0c;根据投资额、投资收益和限制条件&#xff0c;问如何决策使收益最大。"""问题建模&#x…

9. 微积分 - 导数

文章目录 导数求导实例代码演示:迭代法求解二次函数最小值阶Hi, 大家好。我是茶桁。 我们终于结束了极限和连续的折磨,开启了新的篇章。 不过不要以为我们后面的就会很容易,只是相对来说, 没有那么绕而已。 那么,我们今天开始学习「导数」。 导数 在之前的导论,也就是…

【算法竞赛宝典】求分数精确值

【算法竞赛宝典】求分数精确值 题目描述思路讲解代码展示 题目描述 思路讲解 代码展示 //计算分数的精确值 #include<iostream>using namespace std; int remainder[101], quotient[101]; //remainder:存放除法的余数;quotient:依次存放商的每一位int main() {int m, n,…

[CISCN 2019初赛]Love Math

文章目录 前言考点解题过程 前言 感慨自己实力不够&#xff0c;心浮气躁根本做不来难题。难得这题对我还很有吸引力&#xff0c;也涉及很多知识。只能说我是受益匪浅&#xff0c;总的来说加油吧ctfer。 考点 利用php动态函数的特性利用php中的数学函数实现命令执行利用php7的特…

项目验收有哪些流程?

验收流程 科技计划项目验收/课题验收测试服务的被测对象是国家重大专项、科研课题的软件成果物&#xff0c;可以是一个模块、软件或系统等&#xff0c;也可以是软件套件或软件原型等。测试范围主要来源于课题的合同书/可行吧报告/申报书中的技术指标要求。所出具的科技项目验收…

中东 Shopify 如何使用 Bytebase 构建一站式数据库开发工作流

公司简介 Salla 是一家 2016 年成立&#xff0c;位于沙特麦加的自建站电商平台。 作为中东 Shopify&#xff0c;其最大的特点是支持阿拉伯语建站&#xff0c;并且提供更多适应中东地区特点的本地化服务。截止目前&#xff0c;已有 47,000 家店铺入驻 Salla&#xff0c;商品销售…

并发测试工具 apache-jmeter使用发送post请求JSON数据

目录 1 下载安装 2 汉化 3 创建高并发测试 配置线程组 创建web请求 创建监听器 结果树 汇总报告 为web请求添加token 添加Content-Type用于发送json 4 启动测试 5 查看结果 1 下载安装 官网Apache JMeter - Download Apache JMeter 解压运行 2 2 汉化 打开软件…

CS144环境配置问题

使用wsl来做CS144实验&#xff0c;可能会在编译的时候遇到以下问题&#xff0c;很明显是找不到LIBPCAP&#xff0c;参考链接 使用sudo apt-get install libpcap-dev命令下载该库即可。 CMake Error: The following variables are used in this project, but they are set to N…

什么是精益生产?企业如何实现精益生产?

国内的很多制造企业之所以对“精益生产”持怀疑甚至否度态度&#xff0c;大都经历过实施过程中的“水土不服”难题。抛砖引玉讲一下&#xff1a; 1、精益生产的最典型案例 1991年&#xff0c;在当时整个美国处于一种将被“日本人支配”的恐惧背景下&#xff0c;“精益生产”一…

【FPGA项目】第1个项目,来点个灯吧~

前言 你会FPGA吗&#xff1f;我会点灯&#xff01; 一、概述 作为一名点灯高手&#xff0c;今天就来实际操练一下。 如何点亮&#xff1f; 开发板上带有8个LED灯&#xff0c;我们只需要控制它对应的管脚电平输入即可。 1&#xff1a;灭&#xff1b;0&#xff1a;亮。 如何实…

大语言模型之七- Llama-2单GPU(T4 16G)微调(Fine-tune)

模型预训练colab脚本在github主页面。详见Finetuning_LLama_2_0_on_Colab_with_1_GPU.ipynb 在上一篇博客提到两种改进预训练模型性能的方法Retrieval-Augmented Generation (RAG) 或者 finetuning。本篇博客过一下模型微调。 微调&#xff1a;这是采用预训练的LLM并在较小的…

ESP8266+继电器+MQTT+VUE 实现远程开关灯

超详细教程 – ESP8266继电器MQTTVUE 实现远程开关灯 超详细教程 – ESP8266继电器MQTTVUE 实现远程开关灯 接线图 NC&#xff08;通常闭合&#xff09;与COM&#xff08;公共&#xff09;、NO&#xff08;通常开放&#xff09;与COM 是继电器引脚的不同配置&#xff0c;用于不…