Things to pay attention to in time format in Java programming

foreword

In our daily work, time formatting is a common occurrence, so in this article we will take stock of several methods of time formatting in Spring Boot

1. Demonstration of time problem

For the convenience of demonstration, I wrote a simple Spring Boot project, which contains a userinfo table in the database. Its composition structure and data information are as follows: The
insert image description here
project directory is as follows:
insert image description here
The implementation code of UserController is as follows:

@RestController
@RequestMapping("/user")
publicclass UserController {
    
    
    @Resource
    private UserMapper userMapper;

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

The UserMapper implementation code is as follows:

@Mapper
publicinterface UserMapper {
    
    
    public List<UserInfo> getList();
}

The UserInfo implementation code is as follows:

@Data
publicclass UserInfo {
    
    
    privateint id;
    private String username;
    private Date createtime;
    private Date updatetime;
}

The implementation code of UserMapper.xml is as follows:

<?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>

After writing the above content, we have produced a simple Spring Boot project. Next, we use PostMan to simulate calling the UserController interface, and the execution results are as follows:
insert image description here
From the above results, we can see that the display methods of the time fields createtime and updatetime are very "messy", which does not conform to our reading habits, and cannot be displayed directly For front-end users, at this time, we need to format the time.

2. The method of time formatting includes the following 5 kinds in total.

1. Front-end time formatting

If the back-end has the absolute right to speak in the company, or if the back-end is relatively strong, we can forcibly throw the "pot" of time formatting to the front-end to handle.
In order to make this "pot" dump more smoothly (it's a pity that Brother Lei doesn't work as a chef), we can provide front-end engineers with a feasible time formatting method, and the implementation code is as follows.

JS version time formatting

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;
}

Method call:

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

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

2. SimpleDateFormat formatting

In most cases, we still need to be self-reliant and clean the door. At this time, our back-end programmers need to use our strengths. The first time formatting method we provide is to use SimpleDateFormat for time formatting It is also an important time formatting method before JDK 8. Its core implementation code is as follows:

// 定义时间格式化对象和定义格式化样式
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 格式化时间对象
String date = dateFormat.format(new Date())

Next, we use SimpleDateFormat to implement the time formatting in this project. Its implementation code is as follows:

@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;
}

The program execution results are as follows:
insert image description here
From the above results, it can be seen that there is no problem with the time formatting, and it is our expected purpose. But careful readers will find out, why did the return field of the interface change? (The previous field was createtime but now it is ctime...)

This is because after using the #SimpleDateFormat.format method, it returns a String type result, and our previous createtime and updatetime fields are both Date type, so they cannot receive the time formatted result.

So at this time, we need to add two "time" fields of string type to the entity class UserInfo, and then hide the previous time field of Data type. The final implementation code of the entity class UserInfo is as follows:

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;
}

We can use the @JsonIgnore annotation to hide the field, and the execution result after hiding is as follows:
insert image description here

3. DateTimeFormatter formatting

After JDK 8, we can use DateTimeFormatter instead of SimpleDateFormat, because SimpleDateFormat is not thread-safe, and DateTimeFormatter is thread-safe, so if it is a project above JDK 8, try to use DateTimeFormatter for time formatting.

The formatted code of DateTimeFormatter is similar to SimpleDateFormat, and the specific implementation is as follows:

@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;
}

The execution results are as follows:
insert image description here
The difference between DateTimeFormatter and SimpleDateFormat is that DateTimeFormatter is used to format the time type provided by JDK 8, such as LocalDateTime, while SimpleDateFormat is used to format Date type, so we need to use the UserInfoer entity class Make the following changes:

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;
}

We can use LocalDateTime to receive the datetime type in MySQL.

4. Global time formatting

Both of the above two implementations of back-end formatting have a fatal shortcoming. They both need to make certain modifications to the core business class when formatting time. This is equivalent to introducing a new one in order to solve a problem. Question, is there a simpler and more elegant solution?

The answer is: yes. We don't need to change any code, we only need to set it in the configuration file to realize the time formatting function.

First, we find the configuration file application.properties (or application.yml) of Spring Boot. We only need to add the following two lines of configuration to the application.properties configuration file:

# 格式化全局时间字段
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# 指定时间区域类型
spring.jackson.time-zone=GMT+8

After this setting, we restore the original UserInfo and UserController.

The UserInfo implementation code is as follows:

import lombok.Data;
import java.util.Date;

@Data
publicclass UserInfo {
    
    
    privateint id;
    private String username;
    private Date createtime;
    private Date updatetime;
}

UserController implementation code:

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

Then we run the program, and the execution results we see are as follows:
insert image description here
From the above results and code, we can see that we only need to configure it briefly in the program to realize the formatting of all time fields.

4.1 Implementation principle analysis

Why can the formatting of all time fields be realized by setting it in the configuration file?

# 格式化全局时间字段
spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
# 指定时间区域类型
spring.jackson.time-zone=GMT+8

This is because the Controller will automatically call the built-in JSON framework Jackson in the Spring Boot framework when returning data, and perform unified JSON formatting processing on the returned data. During the processing, it will determine whether the "spring .jackson.date-format=yyyy-MM-dd HH:mm:ss", if set, then the Jackson framework will perform time formatting processing when outputting time-type fields, so we can implement it through configuration Formatting functionality for global time fields has been added.

Why specify the time zone type "spring.jackson.time-zone=GMT+8"?

The most realistic reason is that if we do not specify the time zone type, the query time will be 8 hours less than the expected time, because the time zone we (China) is in is 8 hours less than the world time. , and when we set the time zone, our time query will be consistent with the expected time.

4.2 What is GMT?

What does "GMT" mean in time zone settings?

Greenwich Mean Time (GMT) Greenwich Mean Time, also known as world time.

4.3 Greenwich Mean Time

Greenwich is the location of the former Royal Greenwich Observatory in the southern suburbs of London, England, where the prime meridian of the earth is marked, and the starting point for the world to calculate time and longitude. Famous for its maritime history, as the standard point of the Prime Meridian, and after which Greenwich Mean Time is named. The terrain here is dangerous, the scenery is beautiful, and it has both history and local customs. It is also the eastern gateway of London on the River Thames.

Not only astronomers use Greenwich Mean Time, but the term is often used in the news. We know there are local times everywhere. It will be complicated and inconvenient if you use local time to record an important event in the world. And it will be easy to make mistakes in the future. Therefore, astronomers propose a convenient recording method that is acceptable to everyone, and that is to use Greenwich Mean Local Time as the standard.

Mean solar time from mean midnight on the prime meridian. Also known as Greenwich Mean Time or Greenwich Mean Time. The difference between normal time and universal time is equal to the geographical longitude of the place. It was widely used as a basic time measurement system before 1960. Because the earth's rotation rate was once considered uniform, universal time was considered a uniform time before 1960. Due to the influence of the change of the earth's rotation speed, it is not a uniform time system, and it has no theoretical relationship with atomic time or mechanical time, and they can only be compared through observation. Later universal time was replaced by almanac time and atomic time successively, but it is still necessary in daily life, astronomical navigation, geodesy and space flight; at the same time, universal time reflects the change of the earth's rotation rate and is one of the earth's rotation parameters. Still the basic data for astronomy and geophysics.

5. Partial time formatting

In some scenarios, we don't need to uniformly process the global time. In this case, we can use annotations to format some time fields.

We need to add the @JsonFormat annotation to the entity class UserInfo, so that the time formatting function can be realized. The implementation code is as follows:

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;
}

After modifying the code, we run the project and execute the results as follows:
insert image description here
From the above results, we can see that the format of time can also be realized by using annotations. Its implementation principle is similar to the implementation principle of the fourth time format, which is to perform time format processing on the corresponding fields before returning the data.

Summarize

In this article, we have introduced 5 implementation methods of time formatting, the first of which is the front-end time formatting method, and the latter 4 are the back-end formatting methods. The SimpleDateFormat and DateTimeFormatter formatting methods are more suitable for ordinary Java projects. Among them, SimpleDateFormat is not thread-safe, and DateTimeFormatter is thread-safe, but neither of them is the optimal time formatting solution in the Spring Boot project.

If it is a Spring Boot project, it is recommended to use the fourth global time format or the fifth local time format method. Both of these implementation methods do not need to modify the core business code, and only need a simple configuration to complete the time The formatting function is gone.

This article is reproduced from: https://jishuin.proginn.com/p/763bfbd611a0

Guess you like

Origin blog.csdn.net/qq_41774102/article/details/126699980