今天有一个访客预约日期时段的项目出现了bug,经排查得出是js处理日期时间出现了时区的问题,正好当一个总结和笔记记录一下最好的解决方法和原理
由于世界各国和地区所处经度不同,每15经度划分一个时区,总共24个时区,各地区对应的本地时间和时区相关。并且存在不同的时间标准,例如我国使用 UTC 东八区的时间,以北京时间为准,为东8区。实际中国覆盖有东5、6、7、8、9这些时区.
常见的标准时间有两种
1、GMT 格林尼治标准时间GMT是指位于英国伦敦的皇家格林尼治天文台的标准时间,本初子午线被定义在通过那里的经线,由于地球每天的自转有细微的不规则,而且正在缓慢减速,不再被作为标准时间使用。现在的主要标准时间使用 UTC(协调世界时间)。
2、UTC 协调世界时间UTC 是最主要的世界时间标准,由原子钟提供,经过平均太阳时、地轴运动修正 GMT格林尼治标准时间,以「秒」为单位的国际原子时所综合精算而成的时间。一般情况认为UTC和GMT是相等的。
JS 对不同时间标准和日期格式的处理
new Date().toString()
'Tue Jun 24 2025 12:36:11 GMT+0800 (中国标准时间)' 已经加上了东8区
new Date( ).toGMTString()
// 'Tue Jun 24 2025 13:16:11 GMT 基于 0时区
new Date('Mon Apr 17 2022 14:05:26 GMT+0800 (中国标准时间)').toUTCString()
// 2022-04-17T06:05:26.000Z
以上三种方法都会显示一种格林尼治的时间
但是对于同一个日期不同的格式,浏览器解析出来的时间也可能存在差异
在没指定时区的情况下,2025-06-24(符合 ISO 8601)被当做 UTC 0时区处理,转换成东八区,所以加上了8小时,并补上时区指示符;
2025-6-24(符合 RFC2822)被当做本地时区处理,因此不做时区转换,只补上了时区指示符。看下图
new Date('2025-06-24')
// Tue Jun 24 2025 08:00:00 GMT+0800 (中国标准时间)
new Date('2025-6-24')
//Tue Jun 24 2025 00:00:00 GMT+0800 (中国标准时间)
由于浏览器之间的差异与不一致性,强烈不推荐使用Date构造函数来解析日期字符串 (或使用与其等价的Date.parse)。对 RFC 2822 格式的日期仅有约定俗成的支持。 对 ISO 8601 格式的支持中,仅有日期的串 (例如 "1970-01-01") 会被处理为 UTC 而不是本地时间,与其他格式的串的处理不同。
前端处理的方法
方法 | 是否受本地时间影响 | 是否支持统一时区 |
---|---|---|
全部统一本地格式化日期 | 是 | 否 |
.tolISOString |
是 | 否 |
dayjs+timezone |
否 | 是 |
最好使用dayjs+timezone来进行处理,这样无论用户是在哪个地方都会得到固定的时区时间,比如他在东京还是美国都会得到北京标准时间
为什么这种方式不受本地时间影响呢?
因为timezone可以指定使用某个时区(比如 Asia/Shanghai),而不是依赖用户系统时间
它内部根据当前时间和时区规则自动计算偏移量;
例
全局封装一个获取当前东八区时间的方法
// utils/date.js
import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc'
import timezone from 'dayjs/plugin/timezone'
dayjs.extend(utc)
dayjs.extend(timezone)
export function getChinaTime() {
return dayjs().tz('Asia/BeiJing')
}
export function parseChinaTime(str) {
return dayjs(str).tz('Asia/BeiJing')
}
dayjs + timezone 不受本地时间影响,是因为你可以主动指定一个固定的时区(如 Asia/BeiJing),从而绕过浏览器默认使用的本地时区
但是根据实际业务需求并解决不了根本
如果用户把电脑时间调快了一天,now 就会比实际时间快一天;
如果用户把时区改成美国,那 .toISOString()、.toString() 等方法的结果也会跟着变
JavaScript 中的 new Date() 是依赖用户的操作系统时间的,如果用户手动修改了系统时间,前端获取到的时间也会跟着变。
所以如果涉及到预约、支付等关键场景,最好还是从服务器获取时间,也就是调用接口由后端进行返回,之后所有时间判断都基于这个服务器时间。这样无论用户怎么改系统时间,都不影响业务。