如何使不同時區的時間與京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 = 0;
let date = ~~r[3];
if (date === 0) date = 1;
return new Date(Date.UTC(~~r[1], month, date, ~~r[4], ~~r[5], ~~r[6], ~~r[7]));
}
return new Date(input);
}
}
----------------------------分割線-------------------------------
一般而言,我們都以時間戳的方式存儲某個時間。在需要的時候提取出來,根據不同業務需求進行轉化:
function transfromDate(time) {
// 假設time是時間戳,如:1514273945276
let curDate = new Data(time);
// todo
}
這里存在一個潛在問題——改變本機的時區,curDate的值會發生變化!shit!!!
當Date作為構造函數調用並傳入多個參數時,所定義參數代表的是當地時間
MDN
即,構造出的日期用來顯示時,會被轉換為本地時間(調用 toString 方法):
>new Date()
<Tue Dec 26 2017 15:47:50 GMT+0800 (中國標准時間)
GMT AND UTC
GMT+0800是個什么東西呢?我們先來介紹一些可能當年在地理課上學習過的基本概念。
以前人們通過觀察太陽的位置來決定時間(比如:使用日晷),這就使得不同經緯度的地區時間是不一樣的。后來人們進一步規定以子午線為中心,向東西兩側延伸,每 15 度划分一個時區,剛好是 24 個時區。然后因為一天有 24 小時,地球自轉一圈是 360 度,360 度 / 24 小時 = 15 度/小時,所以每差一個時區,時間就差一個小時。
GMT:
最開始的標准時間(子午線中心處的時間)是英國倫敦的皇家格林威治天文台的標准時間(因為它剛好在本初子午線經過的地方),這就是我們常說的 GMT(Greenwich Mean Time)。
然后其他各個時區根據標准時間確定自己的時間,往東的時區時間早(表示為 GMT+hh:mm)、往西的時區時間晚(表示為 GMT-hh:mm)。比如,中國標准時間是東八區,我們的時間就總是比 GMT 時間早 8 小時,他們在早晨 9 點,我們才凌晨 1 點。
所以,GMT+0800 表示早於格林威治時間8小時。
UTC:
但是GMT其實是根據地球自轉、公轉計算的(太陽每天經過英國倫敦皇家格林威治天文台的時間為中午 12 點),不是非常准確,於是后面提出了根據原子鍾計算的標准時間 UTC(Coordinated Universal Time)。
一般情況下,GMT 和 UTC 可以互換,但是實際上,GMT 是一個時區,而 UTC 是一個時間標准。
JS使不同時區的時間與京8區一致
要計算不同時區相對於京8區的時間偏差,我們要借助 Javascript 中的 Date 對象的實例方法 getTimezoneOffset():
getTimezoneOffset() 方法返回協調世界時(UTC)相對於當前時區的時間差值,單位為分鍾。
如果本地時區早於協調世界時(UTC),則該差值為負值,如果晚於協調世界時則為正值
| 東時區 | 格林威治 | 西時區 | |
|---|---|---|---|
| GMT +/- | + | - | |
| getTimezoneOffset() | < 0 | > 0 | |
| 早/晚 | 早 | 晚 |
完整代碼:
/**
* 獲取絕對時間
* 即無論你在哪個時區,得到的時間和京8區的時間一致
*
* @param {Date} time
* @returns {years,month, day, hours, minutes, seconds}
*/
function getAbsTime(time) {
try {
let currentZoneTime = new Date(time);
let currentZoneHours = currentZoneTime.getHours();
let offsetZone = currentZoneTime.getTimezoneOffset() / 60;
if(offsetZone > 0) {
// 大於0的是西區(西區晚) 西區應該用時區絕對值加京八區 重新設置時間
// 西區時間比東區時間晚 所以加時區間隔
offsetZone = offsetZone + 8;
currentZoneTime.setHours(currentZoneHours - offsetZone)
} else {
// 小於0的是東區(東區早) 東區時間直接跟京八區相加
offsetZone += 8;
currentZoneTime.setHours(currentZoneHours + offsetZone);
}
return transfromDate(currentZoneTime)
} catch(e) {
throw e
}
}
部分類容節選自:
https://segmentfault.com/a/1190000004292140
https://www.cnblogs.com/liyunhua/p/4661070.html
