导读: 前后端接口中的时间是怎么约定的?
项目中是否有遇到过时区问题引发的bug?
时间应该遵循什么样的使用规范?
如何理解并处理跨时区问题?
关键字:时间戳、时区、设备本地时间、北京时间
1. 支付宝中的跨时区问题
开门见山举例:
场景1:同笔账单时间不同?
如果我在日本(比北京时间快1小时)使用支付宝,将看到如下效果
- 小荷包 -> 余额:从小荷包中转出一笔到余额, 小荷包中看到的是
19:02
,进到余额中看到的是18:02
- 消息盒子->账单详情:消息盒子提醒我
13:58
发生一笔消费,点进去之后账单详情显示时间是12:58
- 会员积分兑换:一笔兑换记录,Tab2 积分兑换显示的是
19:13
,Tab1 收支明细显示为18:13
为什么以上时间不同?
传输和显示时间的方式不同。有的是后端下发北京时间字符串值,如:"2022-11-14 18:02",有的是后端下发时间戳,由前端转化成最终的时间字符串dateFormat(timestamp, "YYYY-MM-DD hh:mm")
。
场景2:定时场景的时间歧义
如果我在旧金山(比北京时间慢16小时)使用支付宝,将看到如下效果
- 预约转账-提前转:选择
2022-12-31
定时转账,结果提前了1天2022-12-30
就进行了转账。 - 预约转账-转账失败:选择
2022-05-14
给某人转账,结果到了这天,提醒我转账失败了(服务器时间校验未通过)。
为什么会发生上面的情况?
- 用户期望使用旧金山时间"2022-12-31"进行转账,但后端收到之后当做北京时间处理,于是在北京时间"2022-12-31"(对应旧金山时间 2022-12-30)进行了转账。
- 用户传给服务端的时间transferDay 为14号(本机时间13号+ 1) ,服务端需要与另外一个字段nextTaskTime为15号(服务器时间14号+1) 进行对比校验,二者不一致则校验不通过。
灵魂拷问:下列跨时区服务场景中 哪些按北京时间执行?哪些按设备本地时间执行 ?
场景3:账单、凭证类服务
现状:账单、凭证类服务多数是使用的"北京时间"。
- 问题: 大多数同学(前端、后端、产品、业务)不太了解跨时区概念,不知道什么场景使用"北京时间",什么场景使用"设备本地时间"。
问题总结
- 跨时区场景1个应用可能存在2套时间线,导致理解
时间线混乱
,多个应用间理解时间线更加混乱
。 - 定时场景容易出"Bug",用户不理解时区概念,容易发生系统执行时间和用户预期时间
不一致
的情况。 - 业务对跨时区问题感知比较弱,业务、技术同学
不了解
这个使用场景。
上文是支付宝中存在的一些跨时区问题,市面上其他知名APP是怎么处理跨时区问题的呢?
2. 其他APP跨时区问题调研
2.1 调研范围
…
2.2 调研分析
应用 |
调研范围 |
调研分析 |
微信 |
消息列表、会话详情、账单、零钱、朋友圈 |
所有页面全部使用设备本地时间 调研中唯一一个时间使用方式统一的APP |
|
消息页面、QQ空间、收藏页面、交易记录页面 |
消息、QQ空间、收藏中的时间是设备本地时间 消息中的登录时间、交易记录的时间是北京时间 推演:前者的时间属性弱感知,后者时间属性强感知 |
抖音 |
会话页面、退款页面、退款页面、订单页面、足迹页面 |
会话消息、退款详情、退款的时间是设备本地时间 订单详情、订单评价、我的足迹的时间是北京时间 总结:订单时间使用北京时间能理解,但是更明显的趋势是抖音中对于时间使用是没有明显规范的。 |
淘宝 |
会话页面、问大家页面、订单页面、零钱页面、评论页面 |
消息会话、问大家中的时间是设备本地时间 订单详情、零钱账单、精选评论中的时间是北京时间 总结:消息、订单、账单的时间使用对比其他APP有明显相似的趋势,其他服务则没有明显的使用规范。 |
拼多多 |
交易页面、会话页面、浏览记录页面、多多视频评论页、大促评论 |
交易通知、会话消息、评论中的时间是设备本地时间 交易详情、浏览历史中的时间是北京时间 总结: 会话消息、评论、订单的时间使用依然是表现为相似的趋势,除此之外的服务没有明显的使用规范。 |
招商银行 |
账单页面、评论页面 |
使用北京时间 |
中国银行 |
账单页面、资产统计时间模块 |
使用北京时间 |
工商银行 |
账单页面、资产统计时间模块、明细页面 |
使用北京时间 |
支付宝 |
账单、资金业务、咨询、生活服务、常规基础功能服务业务 |
账单、资金相关业务大部分的时间是北京时间 其他基础功能服务、生活服务等普遍存在北京时间和设备本地时间滥用的情况 |
2.3 调研总结
账单类
服务无论是 互联网公司 还是 传统银行 都更倾向使用北京时间消息会话类
服务 更倾向使用 设备本地时间- 国内 互联网公司 中多数并
不care
跨时区问题 - 传统银行 对时间的使用有明显规则 => 使用北京时间
3. 跨时区问题分析
-
什么场景需要关注跨时区问题?
存在一定国际化用户的业务
-
应该效仿微信、银行App全部服务使用 "设备本地时间" 或 "北京时间"?
如果你的服务跟账单关系不大,全部用"设备本地时间"的体验会更好; 如果你是个类似银行类的账单服务,全部用"北京时间"吧能省心很多; 如果你是个类似支付宝的超级应用,那就二者都要有;
- 时间字段使用的规则? 跨时区场景中什么时候使用"设备本地时间" or "北京时间"?
上文的调研分析得出:
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 首次发生 "时区变更" 时(最容易引发“时间理解混乱”的时候) 进行时区信息提示(目的: 与用户对时间信息理解上的达成一致)。
通过分析总结出关于时间使用方面的 "正确姿势" 👇👇👇👇👇👇
4 时间的正确使用姿势
4.1 核心原则&使用规范
核心原则:保障时间理解的一致性
与系统执行时间的准确性
- 理解的一致性:用户心理预期的时间与产品预期传达的时间是一致的。
- 执行的准确性:满足前者的情况下,做到系统真实执行的时间准确匹配产品预期的时间。
前者是产品角度,后者是技术角度。
使用规范:
- "账单"类服务统一使用北京时间,"账单"类服务以外使用设备本地时间。
- 跨时区下使用北京时间的服务需要进行提示,使用设备本地时间的服务在时区变化时需要进行提示。
4.2 时区提示
就不放了…
5. 组件&工具库
就不放了…
5.2 工具库(时间转换)
如果服务端一定要求前端传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区 | 中时区
6. 服务端如何处理跨时区
时间设置,关注时区和时令,避免设置当地值,string传值带时区。
- 时间设置要关注闰年、夏令时、时区。服务器时间都要设置成为UTC(海外)或者GMT+8(国内),一定不能设为当地时间(北美、欧洲、澳洲一些国家都有夏令时)。
- 时间不要用datetime,要用timestamp。用string传时间,一定要ISO格式带上时区信息。
服务器在国外时,严禁使用服务器本地时间(冬夏令时会发生服务器时间跳变),推荐设置为UTC时间。
常见: 服务器在国内时,推荐使用服务器本地时间(GMT+8)。
国内服务器的情况下服务端尽量不感知时区概念, 一概理解成接收和使用的时间都是"北京时间"。
7. 测试回归
就不放了
End
原文链接:https://blog.csdn.net/qq_33559093/article/details/127888999?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522169287040316800226546517%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=169287040316800226546517&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~times_rank-20-127888999-null-null.268%5Ev1%5Ekoosearch&utm_term=%E6%BE%B3%E6%B4%B2%E7%94%9F%E6%B4%BB