2013-08-26 111 views
3

我想用.NET的DateTime結構解析一個ISO8601格式的日期/時間字符串。用DateTime解析ISO8601日期/時間struct

爲了讓我充分認識到這個問題,我將使用.NET和JavaScript進行測試。我目前在英國(英國夏令時,即UTC + 01:00)。

我ISO8601的理解是:

  • 當字符串後綴爲 「Z」,時間是UTC表示。
  • 當字符串後綴爲「+/- hh:mm」時,時間用 表示當地時間,其中「+/- hh:mm」表示與UTC的偏移量。

考慮以下ISO8601日期/時間格式字符串:

"1987-01-05T08:45:30.500+0100" 

鑑於以上我的觀點,這個字符串表示的「8時45分三十〇秒」本地時間和UTC時間「7點45分三十秒」

當前時區測試(.NET)

DateTime now = DateTime.Now; 
Console.WriteLine(now.ToLocalTime()); // 27/08/2013 12:02:43 
Console.WriteLine(now.ToUniversalTime()); // 27/08/2013 11:02:43 

當前時區測試(JavaScript的)

var now = new Date(Date.now()); 
now.toString(); // Tue Aug 27 2013 12:03:46 GMT+0100 (GMT Daylight Time) 
now.toUTCString(); // Tue, 27 Aug 2013 11:03:46 GMT 
從細微

除了(分/秒)的兩個例子之間的差異,他們正在返回正是我所期望的爲英國夏令時間(UTC + 01:00 )。 分/秒的差異是因爲我無法同時運行.NET測試和JavaScript測試。

所以現在讓我用ISO8601的日期/時間格式的字符串:

解析ISO8601格式字符串(.NET)

DateTime dt = DateTime.Parse("1987-01-05T08:45:30.500+0100"); 
Console.WriteLine(dt.ToLocalTime()); // 05/01/1987 07:45:30 
Console.WriteLine(dt.ToUniversalTime()); // 05/01/1987 07:45:30 

解析ISO8601格式字符串(JavaScript的)

var dt = new Date("1987-01-05T08:45:30.500+0100"); 
dt.toString(); // Mon Jan 05 1987 07:45:30 GMT+0000 (GMT Standard Time) 
dt.toUTCString(); //Mon, 05 Jan 1987 07:45:30 GMT 

這似乎不符合顯示日期/時間「現在」的示例。爲什麼在英國夏令時(UTC + 01:00)顯示「現在」示例時,顯示爲我在英國冬令時(UTC + 00:00)?

如果我更改我的時區設置,我會得到本地/世界時間的預期結果,但是如果它們設置爲我當前的時間/區域,這似乎會給出不一致的結果。

編輯:簡而言之,就好像.NET和JavaScript在我嘗試解析字符串時忽略夏令時/英國夏令時(UTC + 01:00)一樣。結果對冬天來說是正確的,當我改變我的時間/地區時也是正確的。但現在這是不正確的「任何」我在英國測試過的機器。

+0

我認爲'+ 0100'被忽略,它可能取決於本地計算機上的'區域設置'。我測試了代碼,它顯示了我07:45:30'與'02:45:30'不像你的測試。 –

+0

這就是你得到的生活/編碼在UTC時區...解析*總是*返回本地時間,但在你的情況下UTC到本地是沒有操作。 –

+0

實際上你的代碼應該是'Local:05/01/1987 07:45:30'和'UTC:05/01/1987 08:45:30','+ 0100'只是表示時間是UTC,因此所有當地時間都將是UTC時間1。 –

回答

2

英國使用夏天的時候在夏季(前進一小時的時鐘)(8月27日,你的「現在」中的例子),但不是在冬季(1月5日,從您的「解析1987- 01-05 T08:45:30.500 + 0100「)。

實際上,在英國使用UTC的冬天。你的機器似乎有英國的TimeZoneInfo。您可以使用TimeZoneInfo.Local.DisplayName(自.NET 3.5)或TimeZone.CurrentTimeZone.StandardName(舊)進行檢查。

您可以用dt.IsDaylightSavingTime()查詢。

增加:

我的回答是有關.NET只(但也許同樣適用於JavaScript的?)。您提供的示例完全按預期工作。 1987年1月的日期和時間將被轉換成你當地的區域,據推測它是英國的,1987年1月英國在冬天以來的時間是+0000。你給的時間字符串加上了+0100(就好像它來自德國或英國以東一小時的其他國家),當字符串被解析時,這被認可了。 1987年夏天的一個日期將正確地進行不同的換算,因爲在1987年夏天,英國(以及所有的歐洲經濟共同體)都觀測到了夏令時(夏令時)。

總結:解釋時間時考慮的偏移指示符或區域說明符+0100。這將在您的計算機上轉換爲英國時間。如果要轉換爲UTC而不是轉換爲本地時間,請使用帶有DateTimeStyles枚舉的過載,幷包含標記DateTimeStyles.AdjustToUniversal

如果你想更好地代表了時間絕對區的值,可以考慮使用,而不是DateTime的結構DateTimeOffset。你也可以考慮NODA時間而不是.NET類型。

+0

這是正確的。我終於搞清楚了,我試圖做的一點是,.NET和JavaScript似乎都不能保留偏移量。因此,您總是會收到UTC時間。我想這是因爲如果偏移量被保留下來,這將與用戶機器不一致。即如果偏移量是+0100而用戶時區是+800,則偏移量(本地/時間)在用戶機器上將不一致......如果這有意義的話? – series0ne

+0

@ series0ne我認爲你錯了。請嘗試將字符串「」1987-01-05T08:45:30.500 + 0100「'更改爲'「1987-07-05T08:45:30.500 + 0100」(夏天)。 ***編輯:***另外,爲了避免混淆,請嘗試使用遠離英國的區域的字符串,比如'+ 1100'或其他。該區域被考慮。 –

+0

我編輯了整個問題,你會介意再看一下嗎?謝謝。 – series0ne

0

ToLocalTime和ToUniversalTime確實考慮到夏令時,並做了很好的工作。至少在.NET中,Javascript Date對象存在缺陷,我建議在js中使用moment.js和moment-timezone.js進行轉換。

這裏是我的單元測試,結果:

 var now = DateTime.Now; 
     Console.WriteLine(now.ToLocalTime()); 
     Console.WriteLine(now.ToUniversalTime()); 

     //Test 1 TimeZone UTC+1 London, etc.. 
     //current day 20th July = BST 

     /* 07/20/2015 01:06:43 
      07/20/2015 00:06:43*/ 

     //set day to 20th Januray UK winter time 

     /* 01/20/2015 01:07:55 
      01/20/2015 01:07:55*/ 

你拿在.net上述結果你就需要一)設定時區爲UTC + 2 B)碰上ToLocalTime()中的毛刺已經修復,MSDN在轉換日期時提到了XP上的缺陷。

終於DateTime.Now返回當地時間,所以使用DateTime.Now.ToLocalTime()有點多餘,你可能會得到意想不到的結果。