2013-03-20 100 views
21

我有一個ISO日期字符串如下如何在解析ISO 8601日期字符串時假定本地時區?

var startTimeISOString = "2013-03-10T02:00:00Z"; 

當我使用它轉換成日期對象在JavaScript下面的代碼,則它返回

var startTimeDate = new Date(startTimeISOString); 

O/P是

Date {Sun Mar 10 2013 07:30:00 GMT+0530 (India Standard Time)} 

它確實將ISOString轉換爲日期,但它轉換爲LO校準時間,因爲新的Date()是依賴於客戶端的。如何將ISO日期時間字符串轉換爲日期和時間,但不是本地日期時間..?

由於

+1

您的ISO時間以'Z'開頭,即UTC(格林威治標準時間)。如果時間實際上是從本地開始的,則應將「Z」替換爲「+0530」。但是如果你想循環訪問你的時間,你應該保持UTC格式的字符串版本。 – 2014-04-11 15:58:04

+0

您能澄清一下,您正在嘗試創建一個保留原始時區的字符串表示形式(在本例中爲祖魯語(Z)),而不是重新解釋運行代碼的計算機時區中的時間。這聽起來像你,但它不是100%清楚。 – 2015-07-10 08:00:29

回答

44

According to MDN:在假定的時區

差異

給定日期字符串「2014年3月7日」,parse()假定本地時間爲 區域,但給定ISO格式(如「2014-03-07」),它將假定UTC時區爲 。因此使用這些字符串 生成的日期對象將表示不同時刻,除非系統設置爲UTC的本地時區爲 。這意味着出現 等效的兩個日期字符串可能會導致兩個不同的值,具體取決於正在轉換的字符串的格式 (此行爲在ECMAScript ed 6中更改爲 ,因此兩者都將視爲本地)。

我曾經做過這樣的,我現在得到的確切時間,這是ISO日期字符串,而不是本地時間

var startTimeISOString = "2013-03-10T02:00:00Z"; 

var startTime = new Date(startTimeISOString); 
startTime = new Date(startTime.getTime() + (startTime.getTimezoneOffset() * 60000)); 

內這將會給ISO日期字符串中相同的日期時,這裏輸出是

O/p

Date {Sun Mar 10 2013 02:00:00 GMT+0530 (India Standard Time)} 
+0

我沒有看到解析函數的細節與此有關。引用的MDN段落只是指出,解析查看字符串的格式並確定格式是RFC2822還是ISO8601。 – 2015-07-10 08:05:31

+0

答案在這裏給出了一天的正確時間,但這很危險,因爲你仍然處於與原始時間不同的時區。正確答案會創建一個與原始時間相同的日期對象。 – 2015-07-10 08:11:41

+0

請注意,getTimezoneOffset是UTC與本地之間的差異,產生與人們預期相反的結果。從MDN開始:「請注意,這意味着如果本地時區在UTC之後,則偏移量爲正值,如果超前,則爲負值。例如,如果您的時區爲UTC + 10(澳大利亞東部標準時間),則返回-600 。「 – 2015-07-10 08:19:27

5

這是因爲日期採用toString方法,其默認返回在本地時區的日期和時間打印。方法toUTCString會給你你需要的字符串。

Date實際上將日期保留爲以毫秒爲單位的unix時間並提供操作它的方法。

+0

我可以將它作爲日期對象而不是字符串嗎?現在它返回一個字符串,但我需要它是一個日期對象,因爲我正在與其他日期進行日期比較 – CrazyNooB 2013-03-20 07:14:34

+0

由於日期對象存儲unix時間,您可以在任何需要的地方使用UTC方法。請參閱Date中的UTC方法:https://developer.mozilla.org/zh-CN/docs/JavaScript/Reference/Global_Objects/Date – Diode 2013-03-20 07:16:27

+0

getUTCDate,getUTCMonth等 – Diode 2013-03-20 07:17:06

9

從tracevipin的帖子總結的對話:

所有Date對象是基於time value是毫秒,因爲1970-01-01T00:00:00Z所以他們UTC其核心。這與UNIX不同,UNIX使用自相同曆元以來代表秒的值。

Date.prototype.toString方法返回一個依賴於實現的字符串,該字符串表示基於客戶端的系統設置和時區偏移(又名本地時間)的時間。

如果需要UTC ISO8601時間字符串,則可以使用Date.prototype.toISOString方法。如果需要,爲這種方法編寫一個「墊片」是很容易的。

最後,不要相信Date.parse來解析字符串。支持ISO8601格式的UTC字符串是在ES5中指定的,但是它在所使用的瀏覽器中並不一致。如果需要廣泛的瀏覽器支持(例如典型的Web應用程序),手動解析字符串要好得多(這並不困難,例如如何操作)。

簡單ISO8601 UTC時間戳解析器:

function dateObjectFromUTC(s) { 
    s = s.split(/\D/); 
    return new Date(Date.UTC(+s[0], --s[1], +s[2], +s[3], +s[4], +s[5], 0)); 
} 

,這裏是爲toISOString墊片:

if (typeof Date.prototype.toISOString != 'function') { 

    Date.prototype.toISOString = (function() { 

    function z(n){return (n<10? '0' : '') + n;} 
    function p(n){ 
     n = n < 10? z(n) : n; 
     return n < 100? z(n) : n; 
    } 

    return function() { 
     return this.getUTCFullYear() + '-' + 
      z(this.getUTCMonth() + 1) + '-' + 
      z(this.getUTCDate()) + 'T' + 
      z(this.getUTCHours()) + ':' + 
      z(this.getUTCMinutes()) + ':' + 
      z(this.getUTCSeconds()) + '.' + 
      p(this.getUTCMilliseconds()) + 'Z'; 
    } 
    }()); 
} 
+0

這樣的庫來實現。你應該把你的正則表達式改爲'/ [\ - \。\ +:TZ]/g' – 2014-02-23 22:57:48

+0

@OnurYıldırım - 你是對的,它沒有正確分割字符串,最簡單的RegExp是'/ \ D /'。它不是作爲一個通用的ISO 8601字符串分析器,這是一個非常大的工作。 – RobG 2014-02-23 23:44:17

+0

ISO字符串和UTC是兩個不同的東西。這不會產生ISO 8601字符串。 ISO 8601編碼的時區,這不會(由於使用getUTC ...) – 2015-07-10 08:14:42

1

在香草javascript沒有辦法創建一個假定您給它的ISO格式字符串的本地時間的日期。以下是將ISO 8601格式的字符串傳遞給javascript時發生的情況。我打算使用非UTC時間,因爲它比使用ISO格式的字符串更好地說明了問題:

  1. var startTime = new Date(「2013-03-10T02:00:00 + 06:00」 )。請注意,這也可以是「2013-03-10T02:00:00Z」或任何其他ISO格式的字符串。
  2. 讀取時間,應用偏移量並計算自1970-01-01T00:00:00Z的毫秒數
  3. 您現在只有毫秒 - 您已經丟失了所有的時區信息。在這種情況下,1362859200000

除了那些給出UTC編號的代碼之外,所有函數都將使用運行代碼的計算機的時區來解釋該數字的時間。

要做什麼原始海報想要的,你需要。

  1. 解析ISO串,解釋偏移(「Z」或「06:00」)作爲時區偏移
  2. 存儲中的時區偏移
  3. 計算和MS存儲紀元以來,使用偏移時區偏移量
  4. 保持該偏移量
  5. 每當嘗試進行計算或打印日期時,應用時區偏移量。

這不是微不足道的,需要8601規範的完整解釋。太多的代碼放在這裏。

這正是moment.js的設計目的。我強烈建議使用它。使用moment.js:

moment("2013-03-10T02:00:00Z").format() 
"2013-03-10T02:00:00Z" 

這將導致打印原始字符串的ISO時間,保留偏移量。

相關問題