2010-05-05 112 views
80

在JS應用程序中,我從服務器(Ajax)接收時間戳(eq。1270544790922)。如何忽略用戶的時區並強制Date()使用特定時區

此基礎上戳我創建使用Date對象:

var _date = new Date(); 
_date.setTime(1270544790922); 

現在,在當前用戶區域設置時區_date解碼時間戳。我不想那樣。

我希望_ date將此時間戳轉換爲歐洲赫爾辛基市的當前時間(不考慮當前用戶的時區)。

我該怎麼做?

+0

我知道赫爾辛基的時區偏移量在冬季爲+2,在夏令時爲+3。但誰知道什麼時候是DST?只有一些在JS – warpech 2010-05-05 09:09:15

+0

中不可用的語言環境機制有可能,但不使用Javascript的本地方法,因爲JavaScript沒有方法來確定其他時區的時區轉換歷史記錄,而不是用戶系統的當前時區(並且它是通過瀏覽器至少當我們進入80年代日期時)。但這種方式是可能的:http://stackoverflow.com/a/12814213/1691517我認爲我的答案給你正確的結果。 – 2012-10-10 08:06:33

+0

http://www.w3schools.com/jsref/jsref_setutcmilliseconds.asp – radpin 2015-09-14 17:30:31

回答

56

Date對象的基礎值實際上是UTC。爲了證明這一點,請注意,如果您輸入new Date(0),您會看到類似於:Wed Dec 31 1969 16:00:00 GMT-0800 (PST)。格林尼治標準時將0視爲0,但.toString()方法顯示當地時間。

大注意,UTC代表通用時間碼。目前在2個不同地方的當前時間與UTC相同,但輸出格式可能不同。

我們所需要的就是一些格式

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me 
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' }); 
// outputs > "6.4.2010 klo 12.06.30" 
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' }); 
// outputs > "4/6/2010, 12:06:30 PM" 

這工作,但....你真的不能使用任何其他日期的方法達到你的目的,因爲它們所描述的用戶的時區。你想要的是一個與赫爾辛基時區有關的日期對象。此時你的選擇是使用一些第三方庫(我推薦這個),或者修改日期對象,以便使用它的大部分方法。

選項1 - 第三方像時刻,時區

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss') 
// outputs > 2010-04-06 12:06:30 
moment(1270544790922).tz('Europe/Helsinki').hour() 
// outputs > 12 

這看起來很多比我們即將下一步要做更優雅。

選項2 - 砍了日期對象

var currentHelsinkiHoursOffset = 2; // sometimes it is 3 
var date = new Date(1270544790922); 
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000; 
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms] 
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset); 
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT) 

它仍然認爲它是GMT-0700(PDT),但是如果你不盯着太辛苦你可以誤以爲,對於一個日期對象,這對你的目的很有用。

我很方便地跳過了一部分。您需要能夠定義currentHelsinkiOffset。如果您可以在服務器端使用date.getTimezoneOffset(),或者只是使用一些if語句來描述何時會發生時區更改,那麼應該可以解決您的問題。

結論 - 我認爲特別爲此目的,你應該使用日期庫,如moment-timezone

+0

...也可以通過簡單地使用來自一個位置的gmt偏移量來完成類似的任務。在這種情況下,你根本不需要JavaScript。 – Parris 2010-05-05 08:50:24

+0

對不起,我的意思是完全相反:)我編輯的問題,也許它現在更清楚 – warpech 2010-05-05 09:01:37

+0

好吧,我改變了我的解決方案。我認爲這是你正在尋找的。 – Parris 2010-05-05 16:47:53

15

爲了說明毫秒,用戶的時區,使用以下命令:

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time 
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need 
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable 
+0

要使用中心的固定偏移來替換,我使用了使用CST創建日期爲00:00的固定時間的概念,然後使用該日期的getUTCHHours。 – grantwparks 2012-07-14 03:36:16

+0

+1這對我有用。不知道「答案」如何在沒有毫秒處理的情況下工作。 – 2013-01-25 11:57:41

+2

@Ehren你不應該添加timezoneOffset去gmt,然後減去中央偏移? – coder 2013-04-11 21:24:07

13

我懷疑,該Answer沒有給予正確的結果。在提問者希望將時間戳從服務器轉換爲當前時間的情況下,不管用戶當前的時區在赫爾辛基。

事實上,用戶的時區可能是我們無法相信的東西。

如果例如。時間戳是1270544790922,我們有一個功能:

var _date = new Date(); 
_date.setTime(1270544790922); 
var _helsenkiOffset = 2*60*60;//maybe 3 
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset); 

當紐約人訪問頁面,警報(_helsenkiTi​​me)打印:

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT) 

而當Finlander訪問頁面,警報(_helsenkiTi​​me)打印:

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST) 

因此函數是正確的只有當頁面訪客在他的電腦上的目標時區(歐洲/赫爾辛基),但卻未能在世界的幾乎所有其他部分。而且由於服務器時間戳通常是UNIX時間戳,根據定義UTC(自從Unix Epoch(1970年1月1日00:00:00 GMT)以來的秒數),我們無法從時間戳確定DST或非DST。

因此,解決方案是DISREGARD用戶的當前時區,並實現某種方式來計算UTC偏移量,無論日期是否在DST中。 Javascript沒有本地方法來確定其他時區的DST轉換歷史記錄,而不是當前用戶的時區。我們可以最簡單地使用服務器端腳本來實現這一點,因爲我們可以輕鬆訪問服務器的時區數據庫以及所有時區的整個轉換歷史記錄。

但是,如果您無法訪問服務器(或任何其他服務器)的時區數據庫,並且時間戳採用UTC,則可以通過在JavaScript中對DST規則進行硬編碼來獲得類似的功能。

爲了掩蓋日期在1998年歲月 - 2099歐洲/赫爾辛基您可以使用下面的函數(jsfiddled):

function timestampToHellsinki(server_timestamp) { 
    function pad(num) { 
     num = num.toString(); 
     if (num.length == 1) return "0" + num; 
     return num; 
    } 

    var _date = new Date(); 
    _date.setTime(server_timestamp); 

    var _year = _date.getUTCFullYear(); 

    // Return false, if DST rules have been different than nowadays: 
    if (_year<=1998 && _year>2099) return false; 

    // Calculate DST start day, it is the last sunday of March 
    var start_day = (31 - ((((5 * _year)/4) + 4) % 7)); 
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0)); 

    // Calculate DST end day, it is the last sunday of October 
    var end_day = (31 - ((((5 * _year)/4) + 1) % 7)) 
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0)); 

    // Check if the time is between SUMMER_start and SUMMER_end 
    // If the time is in summer, the offset is 2 hours 
    // else offset is 3 hours 
    var hellsinkiOffset = 2 * 60 * 60 * 1000; 
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000; 

    // Add server timestamp to midnight January 1, 1970 
    // Add Hellsinki offset to that 
    _date.setTime(server_timestamp + hellsinkiOffset); 
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" + 
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds()); 

    return hellsinkiTime; 
} 

用法示例:

var server_timestamp = 1270544790922; 
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp); 

server_timestamp = 1349841923 * 1000; 
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp); 

var now = new Date(); 
server_timestamp = now.getTime(); 
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " + 
server_timestamp + " and the current local time in Hellsinki is " + 
timestampToHellsinki(server_timestamp);​ 

且不論這種打印以下用戶時區:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30 

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23 

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31 

當然,如果你可以返回ti mestamp以偏移量(DST或非DST之一)已經添加到服務器上的時間戳的形式,您不必在客戶端計算它,並且可以簡化該功能。但記得不要使用timezoneOffset(),因爲那麼你必須處理用戶時區,這不是想要的行爲。

+2

nb。赫爾辛基只有一個'l'。這個錯誤實際上減損了這個答案。 – 2017-03-20 14:31:01

+0

@BenMcIntyre這是一個小笑話。或者應該是這樣的。 :) – 2017-03-21 23:30:12

0

你可以使用setUTCMilliseconds()

var _date = new Date(); 
_date.setUTCMilliseconds(1270544790922); 
+0

這個答案是錯的。 setUTCMilliseconds將指定的毫秒數添加到日期。 – Tibor 2017-03-29 16:11:55

+0

@Tibor:從MozDev:'setUTCMilliseconds()'方法根據通用時間設置指定日期的毫秒數。 [...]如果您指定的參數超出預期範圍,則'setUTCMilliseconds()'會相應地嘗試更新Date對象中的日期信息。換句話說,在UTC創建一個具有給定的Unix時間戳的Date對象。 – jimasun 2017-03-30 08:57:13

+0

從w3schools:setUTCMilliseconds()方法根據通用時間設置毫秒(從0到999)。請嘗試上面的答案並親自查看。 – Tibor 2017-05-04 20:31:42

10

只是另一種方法

function parseTimestamp(timestampStr) { 
 
    return new Date(new Date(timestampStr).getTime() + (new Date().getTimezoneOffset() * 60 * 1000)); 
 
}; 
 

 
//Sun Jan 01 2017 12:00:00 
 
var timestamp = 1483272000000; 
 
date = parseTimestamp(timestamp); 
 
document.write(date);

乾杯!

1

假設你在赫爾辛基時間獲得時間戳,我會創建一個日期對象設置爲1970年1月1日午夜UTC(忽略瀏覽器的本地時區設置)。 然後只需添加所需的毫秒數。

var _date \t = new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)); 
 
_date.setUTCMilliseconds(1270544790922); 
 

 
alert(_date); //date shown shifted corresponding to local time settings 
 
alert(_date.getUTCFullYear()); //the UTC year value 
 
alert(_date.getUTCMonth());  //the UTC month value 
 
alert(_date.getUTCDate());  //the UTC day of month value 
 
alert(_date.getUTCHours());  //the UTC hour value 
 
alert(_date.getUTCMinutes());  //the UTC minutes value

當心以後,總是從日期對象問UTC值。這樣,無論本地設置如何,用戶都將看到相同的日期值。 否則日期值將根據本地時間設置進行移位。