如果我们需要去做时间的国际化,那么肯定存在这样一种情形,即,在绝对时间同一时刻, 但这个时刻在数据库的存储的值是同一个值,在北京和在纽约看到的时间显示是不同的。
看过网上的一些方案,基本认为是两种基本方案,一个是直接传输给前端Long 类型的时间戳,再由客户端获取当地的时区来进行时间的显示。另一种则是传输给前端一个UTC Epoch,类似于这样的字符串-- "gmtModified": "2021-08-20T09:57:16.000+0000"。表示的是某一个时区的时刻,如上面这个字符串,就是表示零时区21年08月20号上午09时57分16秒。
我的意见更加偏向于后者,主要是考虑到Long类型的时间戳存在以下一些问题。
1.如果需要对时间进行基本的运算,如加减一个月,或者7天,Long类型的运算多是数学的加减法,代码可读性低,也容易产生错误。如果将时间戳换算成时间对象去计算的话,就产生了转换的成本,而这个成本是可以避免的。
2.调试时,光看时间戳,开发人员不会产生时间的认识,在开发人员眼中,两个不同的时间戳的数字,只是代表了两个不同的时刻,减少了相对时间的认识。例如,相差多少时间,这两个时间戳分别表示的是什么时候。
较为完整的解决方案:
Mysql 数据库之中存储的时间都是零时区的时间,因为要保证服务端的时间格式一致性。现在每一个mysql的连接,即我们的服务对mysql的连接,对于整个系统来说,仍属于服务端的范畴,但是对于mysql而言,我们的服务是mysql的客户端,所以我们的服务的每一个数据连接都需要显示的设置时区参数。我们目前用的就是东八区,所以,时间在我们服务端的流转也统一使用东八区为宜。
时区的转换一般发生在序列化和反序列化的时候发生,目前来说,只要保证每次序列化和反序列化都按东八区来进行就不会有问题,即需要保证各个服务的时区一致性。
传输给前端的VO需要改变一下序列化策略,应该采用UTC epoch的格式给前端。跟目前的服务端的传输的时间格式相对比的话,就是多了一个时区的信息。
当然,前端传输的数据也应该是时间戳或者UTC epoch。
存在的一些问题:
上面的方案也不是完整的,存在一个问题。即服务端各个服务之间需要遵从同一个时区,如果只是时间的相对运算,例如三天后,8小时候后,一周之后,这个不会有问题,因为每一天都是固定的24小时,每个小时都是固定的60分钟。但是如果是一个月之后或许会有不同,或者是当月有效亦或者11.11当天有效这些判断条件。原因是因为服务端需要保证时区的一致性,而如果客户端是国际化的,那么服务端都以一个时区为准,而客户端是多时区的。在北京的11.11号,和纽约的11.11号是不同的。
在这种情形之下,服务端如果进行时间的计算应该仅限于固定时间的偏移,例如,10s之后,10分钟之后,10小时之后,10天之后。而也会有一些特殊的情况,具体的情形有,年费的会员,怎么计算过期的问题,我看过一种方案,一种是直接取对客户有利的值,即366天,计算的时候在开始的时间戳上加上366天就可以了。
另外一种情况是双十一,这种属于浮动时间,我觉得应该以服务端的时区为准,因为计算发生在服务端之上。即活动通知时,就应注明活动时间为北京时间11月11号,黑色星期五则应以纽约时间黑色星期五为准。