js获取new Date()时区时差问题
- 1. 概念描述
- 格林威治时间
- 时区
- 2. 业务场景描述
- 3. 解决办法
1. 概念描述
格林威治时间
格林威治子午线上的地方时,或零时区(中时区)的区时叫做格林威治时间,也叫世界时。
比如我们中国是东八区,北京时间是(GMT+08:00)
时区
时区是地球上的区域使用同一个时间定义。以前,人们通过观察太阳的位置(时角)决定时间,这就使得不同经度的地方的时间有所不同(地方时)。1863年,首次使用时区的概念。时区通过设立一个区域的标准时间部分地解决了这个问题。
地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早。地球自转一周是24小时,所以划分为24个时区,即东1—12区,西1—12区,相邻两个时区的时间相差1小时
2. 业务场景描述
需要实现一个倒计时抽奖功能,当北京时间为 2024/1/1 00:00:00 的时候,页面“抽奖”按钮可点击。
代码示例如下:
let target = Date.parse('2024/1/1 00:00:00'); // 获取目标时间时间戳
let now = Date.now(); // 获取当前时间时间戳
if( now >= target ) {
// 当前时间大于等于目标时间(即目标时间已经过去)
console.log('开始抽奖')
} else {
console.log('抽奖时间未到')
}
上述代码简单的使用两个时间戳进行比对。如果不考虑时区问题,是正确的。
但如果考虑时区问题,当北京时间已经达到了2024/1/1 00:00:00
,由于不同时区存在着时差,其他时区可能还没到该时间。北京所在时区的已经开始抽奖了,其他时区还在等待时间倒计时。
那么该如何矫正以达到绝对的公平性、同时性呢?
3. 解决办法
方案一:利用时区时差,把本地时间转换为目标时区目标时间
时间,然后进行对比
方案二:统一使用服务器时间
已知格林威治时间,换算本地正确时间
本地时间 = 格林威治时间 - 时差
已知本地时间,换算对应格林威治时间:
格林威治时间 = 本地时间 + 时差
已知本地时间,换算其他时区的时间
因为时区间的差异是以小时为单位的。所以算出0时区的时间后,再减去或加上相应的小时即可(东N区便+N小时,西N区便-N小时)。 为了方便计算,东N区记做正数,西N区记做负数,即:
目标时区时间 = 本地时间 + 时差 + 时区间隔
把本地时间转换为目标时区目标时间时间,然后进行时间比对(如:将本地时间转换为东8区时间)
function convertToTargetTime(timeZone) {
//目标时区(**东时区记做正数,西时区记做负数**)
let zoneOffset = timeZone || 8;
// 本地时间和格林威治的时间差,单位为分钟。 (* 60 * 1000 单位转换为毫秒)
let offset_GMT = new Date().getTimezoneOffset() * 60 * 1000;
// 算出本地当前时间: (单位为毫秒)
let localDate = new Date().getTime();
// 计算时区间隔: (单位为毫秒)
let timeZoneInterval = zoneOffset * 60 * 60 * 1000;
// 转换到目标时区后的时间: (单位是毫秒)
let timeAfterConversion = localDate + offset_GMT + timeZoneInterval;
console.log("东8区现在是:" + timeAfterConversion);
return timeAfterConversion;
}
// 获取目标时间时间戳
let target = Date.parse('2024/1/1 00:00:00');
// 获取转换为东8区的时间戳
let timeAfterConversion = convertToTargetTime(8)
// 时间对比
if( timeAfterConversion >= target ) {
// 当前时间大于等于目标时间(即目标时间已经过去,可以开始抽奖)
console.log('开始抽奖')
} else {
console.log('抽奖时间未到')
}
如此即可保证时间的同时性!