用原生Date对象转换GMT时间到指定时区
时间,这个大家都不陌生的东西,想必很简单?但深究之后,发现里面极其复杂,什么UTC、DST、GMT,各种奇怪的术语,让人措不着头脑,这里当然不会一个个展开来聊,只讲一下怎么把时间转换到另外个时区时间。
UTC时间标准和DST
我们现行的时区标准是UTC,所以经常会看到时间会以GMT+X
的形式表式,例如:Mon Aug 02 2021 09:56:13 GMT+0800 (中国标准时间)
,表示英国格林威治标准时间2021年9月2日上午1点56分13秒再加上8个小时意思。据这种算法,是不是所有当地时间都可以用GMT时间加上时区就行?不是,还有个叫DST的东西,叫做夏时制,简单理解就是每年的夏天,时间都会往前拔一个小时,例如本来是早上九点的,就会显示成早上十点。但并不是所有国家都实行这种制度,所以,如果想把时间从GMT时区转换到另外个时间就会变得非常复杂,我们就可能维护一个DST的数据表来转换时区,像Moment.js、Day.js这类时间库就会这么做,但不想用依赖库的话,有没有简单的办法?
JS内置的Date对象
现代浏览器的Date对象已经非常强大了,基本的get+set功能都具备,例如:setHours
,但却不支持setTimezone
这种方法,也就是说,Date对象由始至终都只能在一个时区内运行(只能是当前浏览器的时区,用户设置,没法通过js转换),但幸运的是有个特殊的函数可以救场,就是toLocalString
,利用他我们就能简单地把当前时区转换到期望的时区。
生成GMT时区时间对象
例如现在GMT时间是2021年8月1日4点32分45秒,我们先用Date.prototype.UTC
方法快速生成一个GMT时间对象(注意:不能直接用setFullYear()
、setHours()
等方法,这些方法都只能设置当前用户时区的时间,不是GMT,setUTCHours()
之类的最好也别用),也可用Date.prototype.parse
方法(注意要加上时区,不然会被视为当前时区,而非GMT),具体函数的使用方法参考MDN文档:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/UTC
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/parse
上代码:
const utcDate = new Date(Date.UTC(2021,7,2,4,32,45));
注意,月周期是0为基数的,所以8月的话,要传7。
生成对应时区时间
有了GMT的时间后,接下来就用Date.prototype.toLocalString
来转换时区了,详细的说明文档请看:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString
这里直接上代码:
utcDate.toLocaleString('en-GB', { timeZone: 'PRC', hour12: false });
解释下几个参数,en-GB
是按英国英语格式生成的时间文本,所以这里生成的格式是这样:02/08/2021, 12:32:45
。然后是timezone
,这里填了PRC
,也就是中国时区了。最后是hour12
,就是转换成24小时制。
输出ISO标准时间
最后就是根据生成的时间文本,取出对应的时间了,我们简简单单地用正则取一下值就行:
const enDateReg = /(\d+)\/(\d+)\/(\d+),\s?(\d+):(\d+):(\d+)/;
const matches = Array.from(dateWithTz.match(enDateReg));
matches.shift();
const days = +matches[0];
let months = +matches[1];
months -= 1;
const years = +matches[2];
const hours = +matches[3];
const minutes = +matches[4];
const seconds = +matches[5];
到这里,你就能据你的需求拼接时间文本了。
最后
但如果反过来,怎么把一个时区的时区转所成GMT时区呢?这个目前来说还没有好的办法,只能使用Date.prototype.parse
来识别,但不能具体到某个地区,我再查查资料有没有好的办法。