时区问题处理

问题描述:程序时间全局使用的 new Date(),在国内一切正常,但是在国外,就出问题了。最后追踪其根本原因为 new Date(‘xxxx/x/x’).getTime() 在不同时区返回的时间戳不一致,导致查询数据失败。

如:new Date("2025/8/1").getTime() 的解析依赖于客户端时区

  • 北京 (UTC+8):解析为 2025-08-01 00:00:00 GMT+0800
  • 纽约 (UTC-4):解析为 2025-08-01 00:00:00 GMT-0400。

结论:相同字符串在不同时区返回不同时间戳(相差时区偏移)

解决方法:

1
2
3
4
5
6
function toUTCTimestamp(dateString) {
const [year, month, day] = dateString.split('/').map(Number);

// 使用 Date.UTC 创建 UTC 时间戳,month - 1是因为 UTC 方法是从 0 开始计算。 减去 8 小时,是因为我们是东八区,兼容历史数据。
return Date.UTC(year, month - 1, day) - 8 * 3600000;
}

到这里你以为获取就解决了,其实不然,通常情况下,一个bug的解决会引出其他bug,现在的情况就是如此。而且这个改动时,我们检查了时间的生成是引用的这个方法,调用也是这个方法,应该是不存在问题的。

可是有其他地方使用了 new Date(时间戳) 就会出现问题,因为客户端在国外还是会根据当前所在的时区来解析,这样就会出问题。分析和解决方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1753977600000 历史数据时间,也就是 UTC 时间减去东八区的8小时的时间。
// 可以理解为 :UTC+08:00 Asia/Shanghai - 上海,这个时间应该是 2025-08-01 00:00:00,但是此时客户端在国外,就解析成了 2025-07-31 19:00:00
new Date(1753977600000);//Thu Jul 31 2025 19:00:00 GMT+0300 (东欧夏令时间)

// 所以必须补上缺失的八小时----------------> 其实不行,这样只能解决在东八区
new Date(1753977600000 + 8 * 3600000);//Fri Aug 01 2025 03:00:00 GMT+0300 (东欧夏令时间)

//最终方案,给他设置时区为原先的东八区
var d_date = new Date(1753977600000);
var beijingDateStr = d_date.toLocaleString("zh-CN", {
timeZone: "Asia/Shanghai"
});
// 从北京时间字符串创建新Date对象,在不同时区得到的都是东八区的时间
var beijingDate = new Date(beijingDateStr);//Fri Aug 01 2025 00:00:00 GMT+0300 (东欧夏令时间)

到这一步,其实所有 new Date() 都可以换成这种toLocaleString方式(其实等同于UTC - 8 小时)。还剩一个最大的问题就是,new Date 直接使用的地方贼多,只能看情况改动了。

划重点: 只要遇到时间相关问题,统一使用UTC(生成和加载),尤其是项目刚刚开始的时候。

回顾分析一下:
new Date().getTime() 返回的是不是GTM?—— 不是!GTM已经被弃用,现在应该都是用的UTC,所以返回的是UTC的时间戳,在哪儿个时区都一样;但是 new Date('xxxx/x/x').getTime() 会根据不同的时区返回不同的时间戳。

收集信息整理总结成表格:

场景 返回内容 时区影响 本质原因 示例值
new Date() Date对象 按本地时区解析 索非亚:Thu Aug 07 2025 07:52:54 GMT+0300 (东欧夏令时间)
北京:Thu Aug 07 2025 12:54:26 GMT+0800 (中国标准时间)
new Date(1754006400000) Date对象 按本地时区解析 北京:Fri Aug 01 2025 08:00:00 GMT+0800 (中国标准时间)
伊斯兰堡:Fri Aug 01 2025 05:00:00 GMT+0500 (巴基斯坦标准时间)
new Date().getTime() UTC时间戳 直接获取当前UTC时刻 1723024000000
new Date('2025/8/1').getTime() 可变时间戳 非ISO格式按本地时区解析 北京:1754006400000
纽约:1754035200000
Date.UTC(2025,7,1) 固定UTC时间戳 直接计算UTC时间戳 1754006400000
new Date(1680000000000).getTime() 原始UTC时间戳 时间戳本质是UTC 1680000000000
new Date('2025-08-01T00:00:00Z').getTime() 固定UTC时间戳 ISO格式明确指定UTC 1754006400000
new Date(2025,7,1).getTime() 可变时间戳 组件构造按本地时区 北京:1754006400000
伦敦:1754017200000
Date.now() UTC时间戳 等同于new Date().getTime() 1723024000000

说明:
ISO格式:仅 YYYY-MM-DDTHH:mm:ss.sssZ 格式能保证一致解析