为什么到了时间你的活动还没开始——探究Date对象

2024-02-01 09:21:44 浏览数 (2)

活动怎么还没开始?!

假设有一个活动,原计划定的是12月25日早上8点开始,结果苹果用户到了早上8点却看见活动按钮还是灰色的,而且PC、安卓都是正常。这种情况如果发生,首先往哪个方向考虑呢?

第一个想到的应该就是new Date传入UTC字符串的坑了:

代码语言:javascript复制
new Date('2019-12-25T08:00')
// pc chrome: Wed Dec 25 2019 08:00:00 GMT 0800 (中国标准时间)
// 苹果手机: Wed Dec 25 2019 16:00:00 GMT 0800 (CST)
// mac safari: Wed Dec 25 2019 16:00:00 GMT 0800 (CST)
new Date('2019/12/25 08:00')
// pc chrome: Wed Dec 25 2019 08:00:00 GMT 0800 (中国标准时间)
// 苹果手机: Wed Dec 25 2019 08:00:00 GMT 0800 (CST)
// mac safari: Wed Dec 25 2019 08:00:00 GMT 0800 (CST)

// 加一个T,safari下就可以算是UTC字符串了

地理常识复习: 格林尼治时间(GMT)的正午是指当太阳横穿本初子午线的时候(格林尼治此时为当地中午12点),有了这个参考点,那么其他任意时刻任意时区的时间都可以推导出来。但是,众所周知,地球不是完美的球体,地球每天的自转也不是完全按照一样的规律的。现在的标准时间一般使用的是由原子钟报时的协调世界时(UTC),UTC时间以原子时秒长为基础。不过GMT、UTC差别不影响生活。

我们也可以看见new Date打印有GMT 0800 (中国标准时间)。因为中国处于东八区,与UTC时间相差8个小时,所以有GMT 0800标记。也就是说UTC时间00:00:00的时候,我们的时间是08:00:00。我们可以把GMT 0800改成GMT 0900,new Date后发现就少了一个小时了。另外,移动端打印的CST表示的就是北京时间了

好了,上面的问题怎么解决。已经知道了传UTC时间出问题了,那么我们就不传UTC时间咯。

时间戳大法好,不过因为难以改变的历史原因,就是给你UTC字符串你怎么办?

首先,中间加一个T就是分割日期和时间,而ios上这就算是UTC字符串了。如果要解决上面的问题,那么我们把它换成空格就好了。但是,又有另外一个坑,IOS上执行new Date('2019-12-25 08:00')会得到invilaid date。处理方法是把2019-12-25转换成2019/12/25的格式:

代码语言:javascript复制
'2019-12-25T08:00'.replace(/-/g, '/').replace('T', ' ')
new Date('2019/12/25 08:00')

如果最后一位加一个Z,则表示的一定是UTC时间,除了ios,pc上也是会加多8小时

代码语言:javascript复制
new Date('2019-12-25T08:00Z')
// pc: Wed Dec 25 2019 16:00:00 GMT 0800 (中国标准时间)

另外,Date.prototype还有一个getTimezoneOffset,顾名思义应该和时差有关。该方法返回与UTC的时差,单位是分。我们处于GMT 8,返回-480 (0 - 8) * 60 = -480

代码语言:javascript复制
new Date().getTimezoneOffset()

所以,上面的问题我们还可以在UTC时间下,使用getTimezoneOffset作为另一个解决方案:

代码语言:javascript复制
// 当判断为苹果设备的时候,使用该方法
if (/iPhone|iPad|iPod|iOS/i.test(navigator.userAgent)) {
    const date = new Date(Date.parse(UTCString)   new Date().getTimezoneOffset() * 60 * 1000)
}

继续研究

看了一下Date对象的prototype的方法,看起来很多,实际上就是get和set了UTC、GMT的年月日时分秒。基本的set、get方法,大家写日期组件应该写过不少了,市面上也有成熟的解决方案如moment。

对于时差问题,我们平时产品如果没有对外的话,一般没什么问题,如果是UTC时间记得转回来就是了。如果涉及到海外,我们尽量还是使用UTC好一些。对于前后端,也是应该传UTC时间的,而且应该传时间戳。UTC时间戳生成方法:

代码语言:javascript复制
// 表示的是UTC时间2019/12/11 11:11:11:011的UTC时间戳
Date.UTC(2019, 11, 11, 11, 11, 11 ,11)

下面,我们看看两地时间如何转换

本地时间 <=> UTC <=> 异地时间

代码语言:javascript复制
// 本地异地以UTC为沟通桥梁
// 本地/异地生成UTC
const UTCString = new Date().toISOString()
// 异地/本地解析UTC
const dateString = new Date(UTCString) 
dateString.toLocaleString() // 格式化为当地时间,toLocaleString有很多配置项

UTC => 本地/异地时间

代码语言:javascript复制
// 某个活动以UTC时间为中心
const UTCTimestamp = Date.UTC(2019, 11, 11, 11, 11, 11 ,11)
// 解析为本地时间
const localTime = new Date(new Date(UTCTimestamp).toISOString())
// 等价于
new Date('2019-12-11T11:11:11Z') // 注意 -
// 格式化时间
localTime.toLocaleString()

Date的prototype上有各种toxxstring,着重看一下toLocaleString、toLocaleTime,它们参数配置项很多,下面总结了一波文档的介绍,快速熟悉这个方法的使用技巧。我们先看几个例子:

代码语言:javascript复制
// 首先,我们先定一个上帝时间UTC
const UTCTimestamp = Date.UTC(2019, 11, 11, 11, 11, 11 ,11)
// 无参数默认当前时区的时间格式化方案
// 


	

0 人点赞