Skip to content

日期格式处理

GoldSubmarine edited this page Jan 10, 2020 · 1 revision

使用Java8日期

Java8引入了新的日期类型,以后,新日期的类型应该会越来越普通的使用。现在准备在项目里也使用java8的日期。

Bean里的时间字段用Instant,具体原因下一节会说明。

国际化情况下的日期使用

假设一个服务部署到了某一时区上的机器上,它会为同一时区,或者不同时区的用户提供服务。

国际化过程中,需要注意两点:

  1. 日期格式数据在处理过程中,不能有信息丢失(类似精度丢失,或者编码转换过程中的数据损失),具体来说就是时区的丢失
  2. 日期展现,比如需要格式化,在前端根据自己的本地环境做。后端处理过程中,使用Unix时间戳,或跟Unix时间戳等价的时间格式就可以了。

满足了上述两点就能保证日期格式处理,不会出问题。

具体方案如下:

  1. 用户在前台选择了日期,如 2019-1-1,表示是用户电脑所在时区的2019-1-1,传给后台的时候,要转成 unix时间戳传给后台。
  2. 后台接受unix时间戳之后,可以选择用Instant或者LocalDateTime+指定时区为东八区 来处理。指定东八区而不是系统时区是因为不同的机器所在时区可能是不同的,指定东八区既固定了时区,也方便我们使用。 但是,系统后台用 LocalDateTime,除了debug时方便看时间外,没什么用,还增加了一个转换环节,即将前台的unix时间戳转换成LocalDateTime。因此,建议直接使用Instant
  3. 数据库字段使用datetime字段。不使用timestamp字段的原因是timestamp字段最大到2038年。不用数字的原因,是方便查询数据用。但是由于datetime 不含时区信息,因此,我们在存入数据库的时候,要指定时区为东八区来转换。这个需要在mybatis里进行配置。
  4. 另外还有一点:数据库表示时区的变量,最好直接指定时区,不要用系统时区。用系统时区可能mysql每次在转换的时候,查一下系统时区,带来额外的开销。这个时区变量跟timestamp有关,跟datetime无关。时区变量变了,timestamp的展示会自动变,但是datetime不会。虽然我们不用timestamp,但是无论数据库的服务器在哪个时区,我们都指定成东八区也是比较合理的。

在上面的方案下,假设有两个用户,一个中国用户,一个日本用户。

  1. 在同一时刻(北京时间晚上6点、日本时间晚上7点),两个用户都在使用系统
  2. 两个用户都在页面上,通过时间选择器,选择时间。默认选择的都是当前时间,北京用户选择了6点(2019-11-11 18:00),日本用户选择了7点(2019-11-11 19:00)。然后提交表单。
  3. 前台将用户选择的时间格式字符串转换成 同一个unix时间戳(1573466400) 传给后台
  4. 后台用Instant接受,不需要日期转换。然后保存到数据,此时按照固定的东八区的时区来格式化时间,都转换成了 北京时间晚上6点(2019-11-11 18:00)保存到数据库了。我们在数据库里看到的是,两个用户都在北京时间6点(2019-11-11 18:00)新建了一条记录。
  5. 当用户查询这条记录的时候,从数据库里查询到的是 北京时间晚上6点字符串(2019-11-11 18:00),转换到Bean的Instant字段的时候,按照固定的东八区时区来解析,解析成1573466400,然后交给前台。
  6. 两个用户的前台浏览器,根据各自的时区,分别将1573466400格式化成2019-11-11 18:00(中国用户)和2019-11-11 19:00(日本用户)。这个过程对用户是不感知的。