前端:时间你用对了吗?

news2025/7/7 2:11:47

导读: 前后端接口中的时间是怎么约定的?

项目中是否有遇到过时区问题引发的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. 跨时区场景1个应用可能存在2套时间线,导致理解时间线混乱,多个应用间理解时间线更加混乱
  2. 定时场景容易出"Bug",用户不理解时区概念,容易发生系统执行时间和用户预期时间不一致的情况。
  3. 业务对跨时区问题感知比较弱,业务、技术同学不了解这个使用场景。

上文是支付宝中存在的一些跨时区问题,市面上其他知名APP是怎么处理跨时区问题的呢?

2. 其他APP跨时区问题调研

2.1 调研范围

...

 

2.2 调研分析

应用

调研范围

调研分析

微信

消息列表、会话详情、账单、零钱、朋友圈

所有页面全部使用设备本地时间

调研中唯一一个时间使用方式统一的APP

QQ

消息页面、QQ空间、收藏页面、交易记录页面

消息、QQ空间、收藏中的时间是设备本地时间

消息中的登录时间、交易记录的时间是北京时间

推演:前者的时间属性弱感知,后者时间属性强感知

抖音

会话页面、退款页面、退款页面、订单页面、足迹页面

会话消息、退款详情、退款的时间是设备本地时间

订单详情、订单评价、我的足迹的时间是北京时间

总结:订单时间使用北京时间能理解,但是更明显的趋势是抖音中对于时间使用是没有明显规范的。

淘宝

会话页面、问大家页面、订单页面、零钱页面、评论页面

消息会话、问大家中的时间是设备本地时间

订单详情、零钱账单、精选评论中的时间是北京时间

总结:消息、订单、账单的时间使用对比其他APP有明显相似的趋势,其他服务则没有明显的使用规范。

拼多多

交易页面、会话页面、浏览记录页面、多多视频评论页、大促评论

交易通知、会话消息、评论中的时间是设备本地时间

交易详情、浏览历史中的时间是北京时间

总结: 会话消息、评论、订单的时间使用依然是表现为相似的趋势,除此之外的服务没有明显的使用规范。

招商银行

账单页面、评论页面

使用北京时间

中国银行

账单页面、资产统计时间模块

使用北京时间

工商银行

账单页面、资产统计时间模块、明细页面

使用北京时间

支付宝

账单、资金业务、咨询、生活服务、常规基础功能服务业务

账单、资金相关业务大部分的时间是北京时间

其他基础功能服务、生活服务等普遍存在北京时间和设备本地时间滥用的情况

2.3 调研总结

  1. 账单类服务无论是 互联网公司 还是 传统银行 都更倾向使用北京时间
  2. 消息会话类服务 更倾向使用 设备本地时间
  3. 国内 互联网公司 中多数并不care跨时区问题
  4. 传统银行 对时间的使用有明显规则 => 使用北京时间

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/9736.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【仁川出差】记2022.10仁川出差

10.16号深圳蛇口港出发,香港机场坐飞机,直达韩国仁川机场。 因为不熟悉,然后人也多,入境时候排队排了很久,出来之后,因为有韩国同事开车来接,解决了第一步怎么到酒店的交通问题。 开车差不多一个…

【快速搭建系列】idea快速搭建struts2框架和测试

idea快速搭建struts2框架和测试示例 步骤 搭建环境 新建一个maven项目 添加maven依赖 pom.xml <!-- ****************struts2框架包*************** --> <!-- struts2-core --> <dependency> <groupId>org.apache.struts</groupId> <ar…

解决 80% 的工作场景?GitHub 爆赞的 Java 高并发与集合框架,太赞了

在工作中&#xff0c;笔者经常和掌握不同技术的朋友讨论具体问题的解决方案&#xff0c;发现在 Java 体系中&#xff0c;大家使用最多的是 Java 集合框架&#xff08;JCF&#xff09;和 Java 并发工具包&#xff08;JUC&#xff09;。实际上&#xff0c;JCF 和 JUC 已经能够覆盖…

曼孚科技入选IDC中国数据智能市场代表厂商

日前&#xff0c;国际知名市场调研机构IDC发布了《Market Glance&#xff1a;中国数据智能市场概览&#xff0c;2022》报告。 报告全面展示了中国数据智能市场的构成与格局&#xff0c;同时遴选出不同细分市场领域的主要技术服务供应商&#xff0c;并依此绘制出市场地图&#…

【window 安装多环境python冲突 -已解决】

简介&#xff1a;在window上面那幢一个python原生环境时没有问题 但是在安装anaconda&#xff0c;就会出现整个环境呗anaconda所占据< 首先我的环境目前装了三个环境&#xff0c;一个是python原生3.7 和3.10的&#xff0c;然后&#xff0c;因为涉及一些操作可能会用到多个版…

MYSQL中LIKE(模糊查询)

0 写在前面 通常我们在搜索的时候总是不会特别精准&#xff0c;例如在百度上搜索&#xff0c;主要搜索关键字&#xff0c;然后加载页面之后再挑选。 所以&#xff0c;在数据库中&#xff0c;有时候会将查询条件不一定直接使用uuid这样的标准查询。实际业务中可能存在模糊查询…

linux笔记(4):东山哪吒开发板(D1-H)测试gpio点亮LED

文章目录1.控制gpio电平高低的流程1.1 选PB2控制LED&#xff0c;对应的编号是GPIO341.2 进入目录 /sys/class/gpio1.3 生成gpio34目录1.4 进入gpio34目录1.5 设置IO方向为输出1.6 控制gpio34(PB2)电平高低附录&#xff1a;linux的GPIO编号和D1-H的IO对用关系参考文档&#xff1…

【vue】Jeecg框架使用过程中的注意事项:

文章目录1.连接后台地址&#xff1a;2.获取接口数据时&#xff1a;3.模糊查询&#xff1a;4.设置默认查询参数&#xff1a;5.数据字典&#xff1a;6.j-date显示时分秒&#xff1a;7.设置添加、编辑、删除、导入等按钮的显示与隐藏&#xff08;按钮权限&#xff09;8.设置列的显…

艾美捷NCTC-135培养基改良版(粉末)相关研究和类别

细胞培养基是生物制药生产的最关键原材料之一&#xff0c;是人工模拟细胞在休内生长的营养环境&#xff0c;提供细胞营养和促进细胞生长增殖的物质基础。培养基主要也括有血清培养基、无血清细胞培养基、化学限定培养基。 无血清细胞培养基的发明是培养基发展史的一个里程碑。无…

如何一键生成活动邀请函的分享链接?

想设计一个活动邀请函但不会编程怎么办&#xff1f;想制作个能播放视频的邀请函要怎么做&#xff1f;今天小编就教你如何使用在线工具乔拓云去制作一个活动邀请函&#xff0c;不仅不用编程而且还有模板能一键套用&#xff0c;下面小编就教你如何使用这个在线工具去制作一个活动…

MongoDB学习二:基本常用命令--增删改查

基本常用命令 查看当前正在使用的数据库命令 db 另外&#xff1a; 数据库名可以是满足以下条件的任意UTF-8字符串。 不能是空字符串&#xff08;“”)。 不得含有’ &#xff08;空格)、.、$、/、\和\0 (空字符)。 应全部小写。 最多64字节。 有一些数据库名是保留的&#xff…

C语言无法实现的泛型编程,C++是如何实现的?模板

1.泛型编程 如何实现一个通用的交换函数&#xff1f; void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(double& left, double& right) {double temp left;left right;right temp; } void Swap(char& left, c…

rt-thread 之------fal移植

rt-thread 之 fal移植 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录rt-thread 之 fal移植前言一、fal是什么&#xff1f;二、移植1.片内flash fal移植step1&#xff1a;使能RT-Thread Components--->中的fal选…

MySQL查询优化实例

| 导语 通过几个小实例&#xff0c;对实际会经常用到的查询进行对比&#xff0c;通过MySQL的执行计划分析语句的执行性能&#xff0c;最后分析几个在实际中会遇到的小问题。 我们知道一般应用系统的读写比列在10:1左右&#xff0c;而且插入操作和一般的更新操作很少出现性能问…

jenkins的安装与配置(超详细)

Jenkins官网&#xff1a;https://jenkins.io/ 或 https://www.jenkins.io/zh/download/Jenkins官网文档&#xff1a;https://www.jenkins.io/zh/doc/jenkins安装包&#xff1a;http://mirrors.tuna.tsinghua.edu.cn/jenkins/redhat/清华镜像&#xff1a;http://updates.jenkins…

SpringMVC学习篇(六)

SpringMVC之全局异常的处理 1 注解方式 1.1 准备工作 1.1.1 导入springmvc依赖和lombok依赖 <dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.22</ve…

Nginx实现四层代理与七层代理

目录 一、实验环境准备 1、准备三台服务器 2、安装nginx环境 3、启动nginx环境 二、设置Nginx七层代理 1、proxy代理服务器配置&#xff08;轮询&#xff09; 2、设置加权轮询 3、健康检测功能 4、解决重复登录问题&#xff08;源地址哈希ip_hash&#xff09; 三、设…

StarRocks从入门到精通系列五:导入数据

StarRocks从入门到精通系列五:导入数据 一、导入总览二、从 Apache Kafka 持续导入三、使用 Apache Spark™ 批量导入四、从 Apache Flink持续导入一、导入总览 下图详细展示了在各种数据源场景下,应该选择哪一种导入方式。 数据导入是指将原始数据按照业务需求进行清洗、…

Springboot常用参数注解

访问路径为http://localhost:8080/ PathVariable GetMapping("/get/{id}/blank/{name}")public Map getValue(PathVariable("id") Integer id,PathVariable("name") String name,PathVariable Map<String,String> kv){Map map new Hash…

在Jeston NX上部署运行PaddleOCR教程(安装whl包方法)

文章目录基本概念介绍1.确定盒子环境pythonCUDAcuDNNTensorRT版本1.1 我还没有安装环境&#xff1a;一步到位整体安装1.2 我已经安装了环境&#xff1a;查询盒子环境版本1.3 默认python版本设置2.安装PaddlePaddle3. 安装PaddleOCR4. 运行例程5. 后续工作附&#xff1a;参考教程…