如何使不同时区的时间与京8区一致?(JS实现)
Update:2019/1/28
更简单的是使用这个函数(toDate):
// 自定义日期格式如下(年月日都必须提供):
// "2011-11-11"
// "2011-11-11 11:11"
// "2011-11-11 11:11:11"
const re_custom = /^(\d{4})-(\d{2})-(\d{2})(?: (\d{2}):(\d{2})(?::(\d{2}))?)?$/;
// iso8601日期格式见:
// http://www.ecma-international.org/ecma-262/5.1/#sec-15.9
const re_iso8601 = /^(\d{4})(?:-(\d{2})(?:-(\d{2}))?)?T(?:(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?)?Z?$/;
const _toString = Object.prototype.toString;
// instanceof Date在跨frame和cypress测试上返回false
function isDate(o) {
return _toString.call(o) === '[object Date]';
}
function toDate(input) {
if (!input) {
return new Date();
} else if (isDate(input)) {
return new Date(input);
} else if (typeof input === 'number') {
return new Date(input);
} else if (typeof input === 'string'){
// 如果是自定义的格式,则用本地时间,
// 否则,使用原生的构造方法(本地还是UTC看具体实现)。
let r = re_custom.exec(input);
if (r) {
return new Date(~~r[1], ~~r[2]-1, ~~r[3], ~~r[4], ~~r[5], ~~r[6]);
}
r = re_iso8601.exec(input);
if (r) {
// month/date缺省值为1月/1日
let month = ~~r[2] - 1;
if (month <0) month &#61; 0;
let date &#61; ~~r[3];
if (date &#61;&#61;&#61; 0) date &#61; 1;
return new Date(Date.UTC(~~r[1], month, date, ~~r[4], ~~r[5], ~~r[6], ~~r[7]));
}
return new Date(input);
}
}
----------------------------分割线-------------------------------
一般而言&#xff0c;我们都以时间戳的方式存储某个时间。在需要的时候提取出来&#xff0c;根据不同业务需求进行转化&#xff1a;
function transfromDate(time) {
// 假设time是时间戳&#xff0c;如&#xff1a;1514273945276
let curDate &#61; new Data(time);
// todo
}
这里存在一个潜在问题——改变本机的时区&#xff0c;curDate的值会发生变化&#xff01;shit&#xff01;&#xff01;&#xff01;
当Date作为构造函数调用并传入多个参数时&#xff0c;所定义参数代表的是当地时间
MDN
即&#xff0c;构造出的日期用来显示时&#xff0c;会被转换为本地时间(调用 toString 方法)&#xff1a;
>new Date()
GMT AND UTC
GMT&#43;0800是个什么东西呢&#xff1f;我们先来介绍一些可能当年在地理课上学习过的基本概念。
以前人们通过观察太阳的位置来决定时间(比如&#xff1a;使用日晷)&#xff0c;这就使得不同经纬度的地区时间是不一样的。后来人们进一步规定以子午线为中心&#xff0c;向东西两侧延伸&#xff0c;每 15 度划分一个时区&#xff0c;刚好是 24 个时区。然后因为一天有 24 小时&#xff0c;地球自转一圈是 360 度&#xff0c;360 度 / 24 小时 &#61; 15 度/小时&#xff0c;所以每差一个时区&#xff0c;时间就差一个小时。
GMT&#xff1a;
最开始的标准时间(子午线中心处的时间)是英国伦敦的皇家格林威治天文台的标准时间(因为它刚好在本初子午线经过的地方)&#xff0c;这就是我们常说的 GMT(Greenwich Mean Time)。
然后其他各个时区根据标准时间确定自己的时间&#xff0c;往东的时区时间早(表示为 GMT&#43;hh:mm)、往西的时区时间晚(表示为 GMT-hh:mm)。比如&#xff0c;中国标准时间是东八区&#xff0c;我们的时间就总是比 GMT 时间早 8 小时&#xff0c;他们在早晨 9 点&#xff0c;我们才凌晨 1 点。
所以&#xff0c;GMT&#43;0800 表示早于格林威治时间8小时。
UTC&#xff1a;
但是GMT其实是根据地球自转、公转计算的(太阳每天经过英国伦敦皇家格林威治天文台的时间为中午 12 点)&#xff0c;不是非常准确&#xff0c;于是后面提出了根据原子钟计算的标准时间 UTC(Coordinated Universal Time)。
一般情况下&#xff0c;GMT 和 UTC 可以互换&#xff0c;但是实际上&#xff0c;GMT 是一个时区&#xff0c;而 UTC 是一个时间标准。
JS使不同时区的时间与京8区一致
要计算不同时区相对于京8区的时间偏差&#xff0c;我们要借助 Javascript 中的 Date 对象的实例方法 getTimezoneOffset():
getTimezoneOffset() 方法返回协调世界时(UTC)相对于当前时区的时间差值&#xff0c;单位为分钟。
如果本地时区早于协调世界时(UTC)&#xff0c;则该差值为负值&#xff0c;如果晚于协调世界时则为正值
东时区
格林威治
西时区
GMT &#43;/-
&#43;
-
getTimezoneOffset()
<0
> 0
早/晚
早
晚
完整代码&#xff1a;
/**
* 获取绝对时间
* 即无论你在哪个时区&#xff0c;得到的时间和京8区的时间一致
*
* &#64;param {Date} time
* &#64;returns {years,month, day, hours, minutes, seconds}
*/
function getAbsTime(time) {
try {
let currentZoneTime &#61; new Date(time);
let currentZoneHours &#61; currentZoneTime.getHours();
let offsetZone &#61; currentZoneTime.getTimezoneOffset() / 60;
if(offsetZone > 0) {
// 大于0的是西区(西区晚) 西区应该用时区绝对值加京八区 重新设置时间
// 西区时间比东区时间晚 所以加时区间隔
offsetZone &#61; offsetZone &#43; 8;
currentZoneTime.setHours(currentZoneHours - offsetZone)
} else {
// 小于0的是东区(东区早) 东区时间直接跟京八区相加
offsetZone &#43;&#61; 8;
currentZoneTime.setHours(currentZoneHours &#43; offsetZone);
}
return transfromDate(currentZoneTime)
} catch(e) {
throw e
}
}
部分类容节选自&#xff1a;