导读: 前后端接口中的时间是怎么约定的?
项目中是否有遇到过时区问题引发的bug?
时间应该遵循什么样的使用规范?
如何理解并处理跨时区问题?
关键字:时间戳、时区、设备本地时间、北京时间
开门见山举例:
如果我在日本(比北京时间快1小时)使用支付宝,将看到如下效果
19:02,进到余额中看到的是18:0213:58发生一笔消费,点进去之后账单详情显示时间是12:5819:13,Tab1 收支明细显示为 18:13
为什么以上时间不同?
传输和显示时间的方式不同。有的是后端下发北京时间字符串值,如:"2022-11-14 18:02",有的是后端下发时间戳,由前端转化成最终的时间字符串dateFormat(timestamp, "YYYY-MM-DD hh:mm")。
如果我在旧金山(比北京时间慢16小时)使用支付宝,将看到如下效果
2022-12-31定时转账,结果提前了1天2022-12-30就进行了转账。2022-05-14 给某人转账,结果到了这天,提醒我转账失败了(服务器时间校验未通过)。
为什么会发生上面的情况?
灵魂拷问:下列跨时区服务场景中 哪些按北京时间执行?哪些按设备本地时间执行 ?

现状:账单、凭证类服务多数是使用的"北京时间"。
时间线混乱,多个应用间理解时间线更加混乱。不一致的情况。不了解这个使用场景。上文是支付宝中存在的一些跨时区问题,市面上其他知名APP是怎么处理跨时区问题的呢?
...
| 应用 | 调研范围 | 调研分析 |
| 微信 | 消息列表、会话详情、账单、零钱、朋友圈 | 所有页面全部使用设备本地时间 调研中唯一一个时间使用方式统一的APP |
| | 消息页面、QQ空间、收藏页面、交易记录页面 | 消息、QQ空间、收藏中的时间是设备本地时间 消息中的登录时间、交易记录的时间是北京时间 推演:前者的时间属性弱感知,后者时间属性强感知 |
| 抖音 | 会话页面、退款页面、退款页面、订单页面、足迹页面 | 会话消息、退款详情、退款的时间是设备本地时间 订单详情、订单评价、我的足迹的时间是北京时间 总结:订单时间使用北京时间能理解,但是更明显的趋势是抖音中对于时间使用是没有明显规范的。 |
| 淘宝 | 会话页面、问大家页面、订单页面、零钱页面、评论页面 | 消息会话、问大家中的时间是设备本地时间 订单详情、零钱账单、精选评论中的时间是北京时间 总结:消息、订单、账单的时间使用对比其他APP有明显相似的趋势,其他服务则没有明显的使用规范。 |
| 拼多多 | 交易页面、会话页面、浏览记录页面、多多视频评论页、大促评论 | 交易通知、会话消息、评论中的时间是设备本地时间 交易详情、浏览历史中的时间是北京时间 总结: 会话消息、评论、订单的时间使用依然是表现为相似的趋势,除此之外的服务没有明显的使用规范。 |
| 招商银行 | 账单页面、评论页面 | 使用北京时间 |
| 中国银行 | 账单页面、资产统计时间模块 | 使用北京时间 |
| 工商银行 | 账单页面、资产统计时间模块、明细页面 | 使用北京时间 |
| 支付宝 | 账单、资金业务、咨询、生活服务、常规基础功能服务业务 | 账单、资金相关业务大部分的时间是北京时间 其他基础功能服务、生活服务等普遍存在北京时间和设备本地时间滥用的情况 |
账单类服务无论是 互联网公司 还是 传统银行 都更倾向使用北京时间消息会话类服务 更倾向使用 设备本地时间不care跨时区问题什么场景需要关注跨时区问题?
存在一定国际化用户的业务
应该效仿微信、银行App全部服务使用 "设备本地时间" 或 "北京时间"?
如果你的服务跟账单关系不大,全部用"设备本地时间"的体验会更好; 如果你是个类似银行类的账单服务,全部用"北京时间"吧能省心很多; 如果你是个类似支付宝的超级应用,那就二者都要有;
上文的调研分析得出:
1. 账单、订单、资金明细、凭证: 使用北京时间
2. 会话消息: 使用设备本地时间
账单类服务相对特殊,需要保持"一致性" 与 "不变性", 同一份账单在不同子应用、跨APP中需要保持一致。🌰:你的转账记录,需要在转账记录、余额、账单、银行账单、电子单、凭证以上所有链路上保持一致。
其次是凭证、电子单、银行流水等部分服务具有一定的法律效力(可能会被当做证据使用)不适合随时区变化。
| 转账记录 | 余额 | 账单 | 银行账单 | 电子单 | 凭证 | |
| 2022-11-01 | 一致:Good | |||||
| 2022-10-30 | 2022-10-30 | 2022-11-01 | 2022-11-01 | 2022-10-30 | 2022-11-01 | 不一致:Bad |
最后得出规则:
1. 账单、订单、电子单、交易明细等 存在"账单"属性的服务使用北京时间
2. 第一点以外的所有服务,包括:消息、实时通知、评论等,都使用设备本地时间
核心问题:业务和用户都不了解跨时区场景,导致跨时区中时间线比较混乱。目标: 解决跨时区场景下时间线混乱的问题。思路:跨时区下使用 "北京时间" and 首次发生 "时区变更" 时(最容易引发“时间理解混乱”的时候) 进行时区信息提示(目的: 与用户对时间信息理解上的达成一致)。通过分析总结出关于时间使用方面的 "正确姿势" 👇👇👇👇👇👇
核心原则:保障时间理解的一致性与系统执行时间的准确性
前者是产品角度,后者是技术角度。
使用规范:
就不放了...
就不放了...
如果服务端一定要求前端传YYYY-MM-DD格式时间(不推荐,推荐传时间戳)的时候
前端不能直接通过dateFormat(timestamp, "YYYY-MM-DD") 格式化之后传值给服务端(这是本机时间的日期,需要传北京时间的日期),可使用这个方法进行转换,避免手动处理时区偏移量
import { getBjByLocalTime } from '就不放了';
/**
* @param timeStr 国外本地时间(YYYY-MM-DD HH:mm:ss)| 时间戳
* @returns dayjs obj
*/
getBjByLocalTime('2022-10-03 12:00') // 日本东京时区
// 返回北京时间dayjs对象
如果服务端只下发了YYYY-MM-DD格式时间(不推荐,推荐下发时间戳)的时候,但业务需要展示本地时间
前端不能直接使用该YYYY-MM-DD格式时间,可使用这个方法把北京时间YYYY-MM-DD 转成 国外本地时间,避免手动处理时区偏移量
import { getLocalByBjTime } from '就不放了';
/**
* 北京时间YYYY-MM-DD 转 国外本地时间
* @param timeStr 北京时间, 支持YYYY-MM-DD HH:mm:ss | 时间戳
* @returns dayjs obj
*/
getLocalByBjTime('2022-10-03 12:00')
// 返回用户本地时区dayjs对象
当业务需要自定义提示用户本地时区,可通过以下方法拿到本地时区的中文信息,如:东京(日本)-东9区
import { getTzNameCn } from '就不放了';
import { getTzStr } from '就不放了';
getTzNameCn() // 返回 纽约(美国)
getTzStr() // 返回 西5区 | 东6区 | 中时区
时间设置,关注时区和时令,避免设置当地值,string传值带时区。
服务器在国外时,严禁使用服务器本地时间(冬夏令时会发生服务器时间跳变),推荐设置为UTC时间。
常见: 服务器在国内时,推荐使用服务器本地时间(GMT+8)。
国内服务器的情况下服务端尽量不感知时区概念, 一概理解成接收和使用的时间都是"北京时间"。
就不放了
End