很多情况下,当你想用日期时,其实很可能需要的是个「精度不高的绝对时间」 。在飞书人力套件的业务中,经常会遇到这种场景 。
例如,一个在美国的同学与一个在日本的同学,都在 2022 年 3 月 22 日这天从公司离职了,由同一个在北京的 HR 办理离职事项 。

文章插图
可见,从我们用户视角理解的「一个事件发生的日期」,其实是我们忽略了时间的精度 。在产品全球化之前,我们通过一些默认的简化,忽略了时间精度的问题(例如把时间都填成 00:00:00) 。一旦面临产品的全球化,就需要补齐时间、提高精度 。
而补齐时间、提高精度的方式,需要根据具体的产品形态具体考虑、明确定义 。
例如,在上述离职场景下,就需要按照这个公司对离职的定义来补充,可以是当地时间当天的 23:59:59,也可以是当天下班时间,如 17:00:00 。
又比如,对于跨团队的业务,例如一个同学的上级汇报线从一个美国 Leader 转到一个日本 Leader,那么为了避免歧义,通常会约定一个确定的生效时区,如统一按照公司的总部所在地的时间来计算 。

文章插图
4. 日期时间的技术实现4.1 确定时区的 DateTime适用于上面的 ①②③④ 四种场景 。

文章插图
所有后端暴露的接口中的时间对象,全部以 UTC 时间表示 。
同时,所有后端在存储、计算、传输时间时,也统一使用 UTC 时间 。由于 DB 存储时间时,时区信息会被丢掉,因此应保证丢掉的时区,是大家明确约定清楚的无歧义的,即 UTC 。这样一来,DB 中的所有时间字段也都没有歧义 。
接口内部产生的时间,例如 CreatedAt、UpdatedAt时间,都应该转换为 UTC 再落盘 。如果直接使用了 MySQL 的NOW()函数,应确保 MySQL Session 的时区设置正确 。
在前端或 BFF 负责处理用户输入的时间,以及展示给客户看到的时间 。包括两个步骤:
- 处理“精度不高的时间”问题 。 比如:员工异动的生效时间,用户只设置到“天”的精度 。那么如果不跨国,可以补全用户会话时区的 00:00:00 为精确生效时间;如果跨国,那就看客户如何定义,以及产品给客户怎样的灵活性:例如,可以以客户公司总部所在地的时区的 00:00:00 为精确生效的时间 。
- 时区转换 。 注意,这里不一定是使用用户的会话时区来转换 。如前面介绍的飞机火车宾馆的预定时间,就要以预定当地的时区来转换 。
不要较真儿抬杠的几点:4.2 不带时区的 Date适用于上面的 ⑤,即纪念日场景 。
由于历史原因,DB 里已经采用北京时间保存了,那么我们可以约定+0800 时区是我们所有后端接口的时间 。只要用一个确定的绝对时区,就不会有歧义,不必非要时 UTC 。
也可以在后端接口的网关层处理时间转换 。不要较真那算不算 BFF,我们需要的是,时区转换逻辑应严禁深入到后端的下层去 。

文章插图
输入或展示时,都不对日期做任何处理 。日期对象直接保存在 DB 中 。
只有真正的纪念日有必要用这种方式,应当非常谨慎 。例如保存一个联系人的生日时 。
5. 关于时区的特殊处理5.1 时区的不确定性使用绝对的时差来表示时区,例如:“东 8 区”表示比世界协调时间(UTC)早 8 个小时的时区 。这是个客观的时区 。
很多时候,我们关注的是一个城市或地区的时区 。例如:Asia/Shanghai 表示中国时间;三字母的缩写 EST 表示美国东部标准时间 。注意,这些根据地理位置定义的时区的时差是会发生变化的,变化因素包括:可能受到当地政策的影响,或夏令时影响 。
对于历史的时间,地理时区是可以确定客观时区的,因为没有人会重新定义已经过去的时间 。
对于未来的时间,地理时区并不能确定客观时区 。因此,如果一个未来的事件是按照非绝对时区约定的,那么它很可能变化 。并且,我们的产品需要考虑到处理这种变化 。
例如,中国员工发起一个“每天早 8 点”的跨国会议,那么在美国,由于夏令时的改变,冬天开会的时间和夏天是不一样的 。反之,美国员工发起的一个“每天早 8 点”的跨国会议,由于美国夏令时的变化,对中国员工的时间也是夏天和冬天不一样的 。
推荐阅读
- 一文搞懂Python中的核心概念:导入,模块,包
- 一文带你搞懂RPC到底是个啥
- 电池|底盘与电池合二为一!一文了解零跑电池CTC技术
- 不懂并行和并发?一文彻底搞懂并行和并发的区别
- 一文看懂智慧城市建设,AI算法如何实现赋能?
- apk 一文带你使用Vue完成移动端项目
- 抓包工具fiddler都有哪些高级功能,一文带你全面了解它
- 一文讲述Pandas库的数据读取、数据获取、数据拼接、数据写出
- 读懂普洱茶常识,别再乱玩儿壶→一张图读懂各种紫砂壶的泥料门道
- 一文搞懂Go通道
