后端返回前端时间格式化

时间格式化的方法总共包含以下 5 种。

1.前端时间格式化

JS 版时间格式化

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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 = newRegExp("(" + 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;

}

方法调用:

1

2

3

4

let date = newDate();

dateFormat("YYYY-mm-dd HH:MM:SS", date);

>>> 2021-07-2521:45:12

2.SimpleDateFormat格式化

使用 SimpleDateFormat 来进行时间格式化,它也是 JDK 8 之前重要的时间格式化方法,它的核心实现代码如下:

1

2

3

4

// 定义时间格式化对象和定义格式化样式

SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// 格式化时间对象

String date = dateFormat.format(new Date())

接下来我们使用 SimpleDateFormat 来实现一下本项目中的时间格式化,它的实现代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

@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 的实现代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

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 类似,具体实现如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

@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 实体类做如下的修改:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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 配置文件中添加以下两行配置:

1

2

3

4

# 格式化全局时间字段

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

# 指定时间区域类型

spring.jackson.time-zone=GMT+8

这样设置之后,我们将原始的 UserInfo 和 UserController 进行还原。

UserInfo 实现代码如下:

1

2

3

4

5

6

7

8

9

10

import lombok.Data;

import java.util.Date;

@Data

publicclass UserInfo {

    privateint id;

    private String username;

    private Date createtime;

    private Date updatetime;

}

UserController 实现代码:

1

2

3

4

@RequestMapping("/list")

public List<UserInfo> getList() {

    return userMapper.getList();

}

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

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

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

1

2

3

4

# 格式化全局时间字段

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 注解,这样就可以实现时间的格式化功能了,实现代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

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 种局部时间格式化的方式,这两种实现方式都无需修改核心业务代码,只需要简单的配置一下,就可以完成时间的格式化功能了。

参考:springboot时间格式化的五种方法总结(解决后端传给前端的时间显示不一致)_java_脚本之家

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

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

相关文章

Python学习从0开始——Kaggle深度学习002

Python学习从0开始——Kaggle深度学习002 一、单个神经元1.深度学习2.线性单元示例 - 线性单元作为模型多个输入 3.Keras中的线性单元 二、深度神经网络1.层多种类型的层 2.激活函数3.堆叠密集层4.构建Sequential模型 三、随机梯度下降1.介绍2.损失函数3.梯度下降法1.梯度下降法…

FL Studio(FL 21)软件下载-详细安装教程视频

​fl studio 编曲软件即,简称FL,是音乐人熟知的水果编曲软件.可以完成完整的音乐制作环境或数字音频工作站(DAW)就是大家熟悉的水果 编曲软件&#xff0c;一个全能的音乐制作软件&#xff0c;包括编曲、录音、剪辑和混音等诸多功能&#xff0c;让你的电脑编程一个全能的录音室。…

海南云亿商务咨询有限公司解锁抖音电商新纪元

在当今数字化浪潮中&#xff0c;抖音电商以其独特的魅力和强大的用户基础&#xff0c;迅速成为企业营销的新宠。海南云亿商务咨询有限公司&#xff0c;作为专注于抖音电商服务的领先企业&#xff0c;凭借专业的团队和丰富的经验&#xff0c;为众多企业提供了高效、精准的电商服…

Keepalived介绍、安装和简单使用

目录 1 Keepalived1.1 keepalived介绍1、keepalived原理2、keepalived原理3、VRRP工作模式 1.2 keepalived安装配置1、安装配置2、keepalived配置文件详解3、通过配置文件实现资源监控 1.3 案例1、nginx keepalived 实现高可用2、nginx keepalived 实现高可用 - 非抢占模式 总…

嵌套查询(一)-谓词IN、量词ANY、量词ALL、比较运算符

一、在多个表之间进行数据查询&#xff0c;除了可以使用连接查询之外&#xff0c;也可以使用嵌套查询&#xff0c;那么什么是嵌套查询呢&#xff1f;如何使用嵌套查询呢&#xff1f; 1、将一个SELECT-FROM查询&#xff0c;嵌套在另一个SELECT查询语句中&#xff0c;那么这个SE…

swagger美化

参考资料 https://doc.xiaominfo.com/docs/quick-start/start-knife4j-version 版本选择 需要先确认springboot版本&#xff0c;再确认swagger版本是2还是3&#xff0c;最后还要关注Springfox的版本。 确认springboot版本的方法 简单的看当前项目使用的就行 例子 https:…

前端面试项目细节重难点(已工作|做分享)(九)

面试官&#xff1a;请你讲讲你在工作中如何开发一个新需求&#xff0c;你的整个开发过程是什么样的&#xff1f; 答&#xff1a;仔细想想&#xff0c;我开发新需求的过程如下&#xff1a; &#xff08;1&#xff09;第一步&#xff1a;理解需求文档&#xff1a; 首先&#x…

这三款使用的视频、图片设计工具,提供工作效率

Videograp Videograp是一款专注于视频生成的工具&#xff0c;特别适合需要快速剪辑和编辑视频的用户。Videograp具备以下特点&#xff1a; 影音比例转换&#xff1a;Videograp支持调整视频的分辨率和比例&#xff0c;使其更适合不同的播放环境和设备。 AI快剪&#xff1a;该工…

期望14K,某小公司java社招面试经历

面经哥只做互联网社招面试经历分享&#xff0c;关注我&#xff0c;每日推送精选面经&#xff0c;面试前&#xff0c;先找面经哥 面试的是一家几百人的公司&#xff0c;基本面试的考察有八股文&#xff0c;也有按照项目问你的&#xff0c;总的来说比较全面吧 1、java代理模式 …

k8s 自动伸缩机制-------HPA 超详细解读

目录 在K8s中扩缩容分为两种&#xff1a; 前言 弹性伸缩是根据用户的业务需求和策略&#xff0c;自动“调整”其“弹性资源”的管理服务。通过弹性伸缩功能&#xff0c;用户可设置对定时、周期或监控策略&#xff0c;恰到好处地增加或减少“弹性资源”&#xff0c;并完成实例…

Android native层的线程分析(C++),以及堆栈打印调试

文章目录 Android native层的线程分析(C)&#xff0c;多线程实现1.native线程的创建第一部分&#xff1a;android_thread模块第二部分&#xff1a;linux_thread模块 2.测试linux_thread模块3.Android native的Thread类3.1源码分析 4.native层堆栈调试方法1. 引用库2. 头文件3. …

前端实现获取后端返回的文件流并下载

前端实现获取后端返回的文件流并下载 方法一&#xff1a;使用Axios实现文件流下载优点缺点 方法二&#xff1a;使用封装的Request工具实现文件流下载优点缺点 方法三&#xff1a;直接通过URL跳转下载优点缺点 结论 在前端开发中&#xff0c;有时需要从后端获取文件流&#xff0…

性能测试3【搬代码】

1.Linux服务器性能分析命令及详解 2.GarafanainfluxDB监控jmeter数据 3.GarafanaPrometheus监控服务器和数据库性能 4.性能瓶颈分析以及性能调优方案详解 一、无界面压测时&#xff0c; top load average:平均负载 htop 二、Garafana监控平台 传统项目&#xff1a;centosphpm…

网站接口是怎么开发的,开发之后是怎么用的

网站接口的开发流程 1.确定接口需求 在开发接口之前我们先要知道&#xff0c;要开发什么样的接口&#xff0c;这个接口是用来干什么的&#xff0c;得先知道相关的需求&#xff0c;才能规划下一步&#xff0c;比如客户想要一个文章列表&#xff0c;那么我们就知道这个需求…

kettle从入门到精通 第六十九课 ETL之kettle kettle cdc mysql,轻松实现增量同步

1、之前kettle cdc mysql的时候使用的方案是canalkafkakettle&#xff0c;今天我们一起学习下使用kettle的插件Debezium直接cdc mysql。 注&#xff1a;CDC (Change Data Capture) 是一种技术&#xff0c;用于捕获和同步数据库中的更改。 1&#xff09;Debezium步骤解析mysql b…

基于Python+OpenCV高速公路行驶车辆的速度检测系统

简介&#xff1a; 基于Python和OpenCV的高速公路行驶车辆的速度检测系统旨在实时监测高速公路上的车辆&#xff0c;并测量它们的速度。该系统可以用于交通监控、道路安全管理等领域&#xff0c;为相关部门提供重要的数据支持。 系统实现&#xff1a; 视频流输入&#xff1a;系…

Antd 自定义列表全选功能

背景 需要为List组件自定义全选功能&#xff0c;如下图所示&#xff1a; 全选checkbox需要与下面每一项的checkbox联动&#xff1b;当从第一页翻页到第二页的时候&#xff0c;第一页已选的内容保持&#xff0c;可以对第二页勾选&#xff0c;同时保证全选checkbox的状态是正确的…

当JS遇上NLP:开启图片分析的奇幻之旅

前言 在当今科技飞速发展的时代&#xff0c;JavaScript&#xff08;JS&#xff09;作为广泛应用的编程语言&#xff0c;展现出了强大的活力与无限的可能性。与此同时&#xff0c;自然语言处理&#xff08;NLP&#xff09;领域也正在经历着深刻的变革与进步。 当这两者碰撞在一…

【并发编程系列一】并发编年史:线程的双刃剑——从优势到风险的全面解析

文章目录 并发简史&#x1f5a5;️初期探索&#xff08;20世纪50-60年代&#xff09;并发理论基础&#xff08;1965年以后&#xff09;并行计算的兴起&#xff08;1970年代至1980年代&#xff09;现代并发技术&#xff08;1990年代至今&#xff09; 线程的优势&#x1f60d;发挥…

DDei在线设计器-API概述

API文档 本文档提供了DDei组件所包含的关键API接口&#xff0c;以及重要类之间的关系&#xff0c;并以可运行示例代码的形式说明API的调用&#xff0c;便于开发人员进行查阅、调试和复制。 如需了解详细的API教程以及参数说明&#xff0c;请参考DDei文档 设计器 设计器API用于…