前后端传递时间参数的正确姿势,别用yyyy-MM-dd HH:mm:ss了

1,825 阅读3分钟

很多项目在前后端传递时间参数的时候都会使用yyyy-MM-dd HH:mm:ss格式,好像也没啥问题,没问题的原因是你们只在中国(固定时区)访问,如果你们的项目是全球化的,那么就会出现问题,这里就不展开说了。 时间传递问题同时涉及前后端,所以本文也会附上前后端(Java)代码,如果你的服务端同事不配合,请将本文转发给他。

yyyy-MM-dd HH:mm:ss 的问题

  • 时区问题,如果前后端不在同一个时区,或者前端被多时区地区访问,那么就会出现时间不一致的问题
  • format 问题,服务端在接收和返回时都要给时间字段指定格式,前端请求时也要指定格式,这一步其实没啥意义。

不太优雅的数字时间戳

有经验的朋友会立即提出使用时间戳,时间戳是无时区的,前后端交互时间字段用数字类型的时间戳,简单解决时区问题,但是这样的话还是有两个小问题。

  • 数字类型的时间戳可读性差,不利于调试
  • 服务端接收和返回要额外将时间戳转换成日期格式,前端请求时也要将日期格式转换成时间戳,这一步其实也没啥意义。

破局 ISO 8601

ISO 8601 格式是国际标准化组织(ISO)制定的日期和时间的表示方法,它的格式如下:

# 2023-10-01T00:00:00.000Z
YYYY-MM-DDThh:mm:ss.sssZ

这里T表示日期时间分隔符,Z表示是个UTC时间,也就是零时区时间,如果不加Z,那么就是本地时间,比如2023-10-01T00:00:00.000表示北京时间,如果你在美国,那么就是美国时间,这里不深入了,有兴趣的朋友可以自行Google。

前端如何使用 ISO 8601

前端使用 ISO 8601 非常简单,只需调用Date对象的toISOString方法即可,如下:

const date = new Date()
const str = date.toISOString() //2023-10-16T07:00:25.507Z
const obj = {
    name: "张三",
    date: str
}

服务端如何使用 ISO 8601

服务端使用 ISO 8601 也非常简单, 首先抛弃旧观念,不要在需要和前端交互的接口使用LocalDateLocalDateTime对象,而是使用Instant类型。

package com.example.demo.model;
import lombok.Data;

@Data
public class UserInfo {
    private String name;
    private Instant date;
}

这样就可以直接接收 ISO 8601 格式的时间了,再也不需要@JsonFormat@DateTimeFormat指定转换格式了。

PS

Instant 类型可以同时接收时间戳(秒级)和ISO 8601格式的时间,如果你的前端同事不配合,那么你无需修改就可以直接使用时间戳,如果你的前端同事配合,那么你就可以使用ISO 8601格式的时间。

结语

这样就解决了前后端时间传递的问题,同时也解决了时区问题,不需要额外的转换格式,也不需要额外的格式转换,是不是比以前优雅呢?