
文章插图
前言
在和前端同学联调的过程中,我们通常会遇到与时间有关的场景:为什么传过来的时间落库的时候总是1970年?为什么相同的时间戳在不同的区域里转换成的时间字符串不一样?为什么不同的转换方法换成的结果一会是GMT,一会是UTC?
时间,这个在开发中不起眼的一环,却又往往会让很多开发者在遇到时犹豫不决 。
在本文开始之前,先抛出一个问题:在日常的业务场景中,什么场景使用北京时间?什么场景使用本地时间?
GMT与UTC
我们先来复习一下以前的地理知识:
我们知道,地球分为24 个时区,一个时区的范围是十五个经度,地球又分东西半球 , 东西半球各占十二个时区;每个时区相差一个小时,最多相差24小时,也就是一天 。
凡向西走,每过一个时区,时间要慢一个小时 , 就要把表拨慢1小时(就是说你所在的位置是两点,向西一个时区就减去一个小时,也就是一点);凡向东走,每过一个时区,时间要快一个小时,就要把表拨快1小时(比如1点拨到2点) 。
而这一切的起点,就在英国伦敦,那里有一条世界上著名的线,叫本初子午线,是人类世界计算时间的起点(时区的划分)以及经度的起点 。而这条线的划定是由格林尼治天文台确定的,因此格林尼治天文台所在的地方叫零时区 。零时区表示为GMT+00,零时区缩写叫z 。

文章插图
所以GMT,即Greenwich Mean Time,格林尼治标准时间(格林尼治所在地的标准时间) 。
以格林尼治天文台所在的时区为中心(GMT+00),向东为正,向西为负;零时区比东时区晚,比西时区早 。
北京所在的时区叫东八区,东八区表示形式是:GMT+08 。0时区比东八区的时间晚8小时,比西五区的时间早5小时 。美国华盛顿比北京慢13小时 。
UTC全称Universal Time Coordinated,是国际无线电咨询委员会制定和推荐的,UTC相当于本初子午线(即经度0度)上的平均太阳时 。它是经过平均太阳时(以格林威治标准时间GMT)、地轴运动修正后的新时标以及以「秒」为单位的国际原子时所综合精算而成的时间,计算过程相当严谨精密 , 因此若以「世界标准时间」的角度来说,UTC比GMT来得更加精准 。
所以,简单来说,UTC就是一个比GMT更加精确的时间表述 。
说完了人类世界的时间表示,我们来看看计算机世界的时间表述 。
认识二进制世界中的时间

文章插图
这种表述方式被称为Unix时间(Unix Time),也叫做POSIX时间或,是用来记录时间的流逝,定义为从UTC时间1970年1月1日0时0分开始流逝的秒数,不考虑闰秒 。
上述图中,有一个很不起眼但很关键的一个点:t=0时刻 。这个时刻为1970年1月1日0时0分 , 被称为纪元时间(epoch time) 。从定义可以看到它只代表了从Unix纪元开始流逝的秒数,所以你身处地球上何处,这个时间都是一样的 。
有一点值得注意的是,Unix纪元是Unix或类Unix系统,一些C/C++,Java等编程语言使用的纪元 。而其他的操作系统或者编程语言,使用的就是不一样的纪元起始日期了 。
例如:Microsoft C/C++ 7.0 使用的是 1899年十二月31号
时区转换
既然地球上的不同时区所处的时间是不一样的,那么计算机在处理跨时区问题时就需要做时区的转换 。在我们对时区问题抽象之前,我们可以先看看跨时区可能会出现什么异常?
跨时区可能会出现什么异常?
问题1:跨时区引发的展示异常
如果在日本(比北京时间快1小时)使用淘宝下单,看到的时间是日本时间还是北京时间?支付服务是按照北京时间还是日本时间执行?
问题2:时间错乱引发的处理异常
在旧金山(比北京时间慢16小时)的用户A计划在2023-01-01给北京的用户B预约一笔转账计划,但后端收到之后当做北京时间处理,于是在北京时间"2023-01-01"(对应旧金山时间 2022-12-31)进行了转账,于是用户B提前了1天2022-12-31就收到了转账 。
对跨时区问题的抽象处理

文章插图
在上述场景中,有几个不同的时间,接下来我们一一阐述
- 用户的时间(客户端)与服务器的时间(展示与计算)
- 服务器与服务器的时间(跨时区计算)
- 服务器与数据库的时间(计算与存储)
Web Server => Client
- 若二者时区相同(已将server服务器设置为当地时区) , 那么可以在server端将时间格式化为字符串字面量直接传输到client端展示 。其中,若server端时间为其他时区的字符串字面量时,需转为当前时区;若为Date对象,直接format,Java默认取当前系统时区;若为毫秒long , 转为Date再格式化
- 若时区不同,server端将时间转换成毫秒数long或者字面量+时区,传输到client,由client所处的时区进行转换处理,最终展示 。
如用户通过前端时间控件选择的时间,需要转化为毫秒数long或者字面量+时区,传输到server端 。
Server-n <=>Server-k
取决于时间的序列化和反序列方式,如dubbo所使用的hession序列化方式会将Date对象序列化为毫秒数、json将时间序列化为字符串(需要指定时区)
Server-n <=> DB

文章插图
数据库时间最常用的字段类型有bigint、datetime和timestamp
- bigint用于自己维护一个时间戳,8字节的长度让其使用几乎无上限,因此使用bigint不存在时区问题,可以使用;
- datetime字段以字符串格式存储,对应应用层String,无时区属性,在多时区场景下传输与转换不建议使用;
- timestamp字段以时间戳格式存储 , 对应应用层Date类型,与系统时区无关,但需要注意的是,由于4字节的长度导致存储的时间上限为2038-01-19 03:14:07 , 需做好对应的处理 。
时间序列化和反序列化
上文提到使用bigint不存在时区问题,因此这里我们来重点讨论下datetime和timestamp在时间存储与读取时所遇到的序列化与反序列化的情况
- DateTime类型字段,MySQL存储时不存时区信息,并且怎么存就怎么?。?不做任何处理和转换 。所以时区timeZone1的server1插入MySQL一条记录后,时区timeZone2的server2读取出来的时间就不对了 。这里只能将所有的server的时区设置为一样的 , 或者在数据库表中添加一个字段存储时区信息
- TimeStamp类型字段,这个比较特殊 。当server创建connection时 , 可以在数据库URL中手动指定时区信息,即不同时区的server连接MySQL时,指定connection时区使用自己所在时区 。当MySQL处理不同的connection时 , 就有了时间字符串和发出请求的时区,然后转换为UTC时间进行存储 。从MySQL中读取时也是基于connection的时区设置进行转换 。但是如果不指定connection时区,那么MySQL就将存储的UTC时间,按MySQL服务器所在时区进行转换和展示或者传输,此时若MySQL服务器和server的时区不一致,就会出现时区问题
跨时区场景应用调研
了解了跨时区场景的处理后,我们来看看业内产品是如何处理跨时区业务的 。
业内App
结论
通讯类
微信、QQ
- 微信统一了app内所有的时间:使用设备本地时间
- QQ消息、QQ空间、收藏中的时间是设备本地时间,消息中的登录时间、交易记录的时间是北京时间
抖音、淘宝、拼多多、亚马逊
- 会话消息、退款详情、退款、交易通知、评论等服务使用设备本地时间
- 订单、交易详情使用北京时间
招银、中银、工银、paypal
- 银行统一使用北京时间
- paypal 支持 手动 设置时区
1. 非金融类的app不太关心跨时区场景?
常规业务对于时间点信息的感知偏弱,更倾向于感知距离“现在”的时间差(消息、评论等),不同的服务有各自对应的最佳“时区”搭配 。
2. 银行类App的时间是统一使用“北京时间”?
国内银行类服务、金融类服务(基金、股票)有强制使用北京时间的诉求 。
3. 国际化业务有时区设置能力?
可?。?国际化业务中一般在时间信息之后回携带上时区信息(如:时区偏移量、城市信息), 移动端服务 常见的是跟随设备的时区 , 部分服务商会在业务中提供出选择时区的能力 。
4. 衡量使用北京时间和设备本地时间的标准是什么?
业内暂无具体的标准,合规、安全也没有详细要求,最佳的是站在用户体验角度case by case去分析 。
总结
国际化背景下多时区问题日益严重,多时区引发的问题一般不易发现,发现时已经灾难性问题,应对及改造成本也较高 。架构层面尽量规避时区问题,在系统设计阶段需要考虑并遵循相应的原则 。
DB层面:
- 新增表或字段时需要对时间类型慎重选择 , 非跨时区场景建议选择datetime,跨时区场景可以选择timestamp或bigint 。
- 对于VARCHAR类型时间字符串都必须使用iso标准时间格式 。
- 新建库的DB时区需为UTC时区,不能使用其他时区(如LA时区) 。
- 新建应用的服务器时区需为UTC时区 。
- 应用内部以及应用与应该之间,统一使用Date对象或iso标准时间格式字符串来传递属性 。
- 只需要年月日信息的日期属性,请定义为String类型,不要定义为Date类型 。
- 牡丹吊兰有毒吗,心叶日中花有毒吗
- 冰块怎么做不容易化,怎样让冰块保持不融化
- 抖音怎么制作手动翻照片,抖音图集怎么搞成自己翻?
- 中筋粉和高筋粉的区别有哪些,高筋面粉和中筋面粉的区别
- 锂保存在哪里,锂单质存放在哪?
- 老公生日送什么礼物,送老公生日礼物送什么比较有意义
- 炒蚬子用不用焯水,辣炒蚬子 是先煮一下呢 还是直接炒
- 雅泰角鲨烯胶囊的功效,角鲨烯软胶囊的功效与作用
- 海上交通与陆上交通相比,明显的优势有,陆上运输与海上运输的优势各是什么
- 中国五大名酒,中国五大名酒是什么?
