2014-02-18 131 views
3

我很努力地將DateTime轉換爲UTC,這個概念和所有東西,我沒有正確理解。如何正確地將日期轉換爲UTC,然後將其轉換回來?

當我得到一個日期時間字符串,說:「2013年7月10日」,我簡單地做

Convert.ToDateTime("7/10/2013").ToUniversalTime(); 

這會將其記錄爲「2013年7月10日上午04時○○分00秒 「在數據庫中。服務器位於美國東海岸(-5)。當然,7月2013時,仍在觀察DST,在這段時間,所以偏移爲-4,這種額外的4小時上午4點零零分00秒「記錄爲UTC。

正如我在寫這如果我將-5偏移量應用於「7/」,那麼這是2014年2月,DST沒有生效,所以現在抵消了-5。在我的應用程序中,這是我在我的應用程序中選擇的偏移量。/2013 4:00:00 AM「,日期將是」7//2013 11:00:00 PM「。

哪一個錯誤,並關閉一天。

問題#1

那麼如何做我正確地轉換UTC時間回來?意思是,當用戶現在在2014年2月加載我的應用程序(當前時區偏移-5)時,2013年7月10日上午4:00:00應該仍然是7/10/2013,而不是7/09/2013。

令我困惑的是,因爲.ToUniversalTime()將服務器DST考慮在內,是否存在硬件集「通用時間」,它不受服務器位置的影響?

問題2

會發生什麼事,當我有兩個西部和東部沿海服務器寫入數據庫?如果應用程序記錄的UTC時間是基於東或西海岸的話,應用程序如何能夠說明問題?

基本上,代碼如何告訴,「7/10/2013 4:00:00 AM」是在東海岸創建的UTC時間(表示2013年7月10日00:00:00 AM)東海岸),而不是在西海岸的一臺服務器(這表明它是美國西海岸的7/9/2013 20:00:00 pm)?

對不起,如果這聽起來很愚蠢。

==========最後的編輯,我目前的解決方案===============

的MiMo的回答是有道理的。我用兩件事情混爲一談。

  1. UTC時間存儲在數據庫中意味着什麼到服務器?
  2. 服務器的時間與應用程序用戶的關係是什麼?

我的應用程序可以被不同時區的用戶使用,有些用戶與服務器在同一時區,有些用戶不在。有些旅行,即使他們與服務器處於同一時區,他們可能會一直在不同的時區登陸。我的應用程序允許他們選擇他們在哪個時區,並適當反映時間。

最初,我只是從數據庫中獲取UTC時間,並從中減去用戶的時區偏移量。正如Mimo所說,這是錯誤的。原因可以在我上面的帖子中看到。

我原來的解決方案是現在得到服務器的時區偏移量,並使用它從UTC加/減,這也是錯誤的。截至2013年10月7日,服務器當時的偏移量爲-4。現在,在2014年2月,服務器時區偏移量爲-5。解決這個當然是使用.ToLocalTime()

之前,我深入挖掘米姆的關於如何使用TimeZone.ToLocalTime(建議),這裏是我做過什麼,暫時解決問題。

  1. 從數據庫中獲取UTC日期並將其轉換爲.ToLocalTime,即服務器顯示的日期。所以到服務器,7/10/2013 4:00:00 AM變成7/10/2013 12:00:00 AM。

  2. 獲取服務器時區偏移量。它目前顯示-5,因爲它在美國東海岸。

  3. 獲取用戶的時區偏移量。對於西海岸,用戶現在選擇-8。對於東海岸,用戶現在選擇-5。

  4. 獲取用戶的時區和服務器的時區之間的差異。西海岸是-3。東海岸爲0.

  5. 減去7/10/2013 12:00:00 AM之間的差異,因此西海岸的截止日期爲2013年9月7日21:00:00,東海岸的截止日期爲7/10/2013 12:00:00 AM。

全部正確。

非常感謝。現在可以深入研究TimeZone.ToLocalTime()並查看是否可以減少步驟2-5。

+0

按照離開時間(物體)單獨計算並僅以UTC顯示時間。 – Bit

+0

保存日期/時間的列的SQL數據類型是什麼? – wdosanjos

回答

2

您使用ToLocalTime()轉換回本地時間。它會看到日期/時間是在七月,因此使用DST,因此它將會移動4個小時而不是5個。

如果您有連接到服務器的客戶端(例如Web瀏覽器),您將最終希望將日期/時間轉換爲客戶端的本地時間,而不是服務器的本地時間。要做到這一點,最好的方法是使用TimeZone.ToLocalTime():發送到客戶端所在的時區,然後直接轉換到該時區。

從不加/減小時 - 總是經過時區並使用TimeZoone.ToLocalTime()。涉及DST時,加/減小時不起作用。

請注意,無法從瀏覽器中獲取當前(本地)時區。如果您的客戶端是瀏覽器,您需要從某種配置中獲取時區或讓用戶輸入它。

還要注意,一旦你開始處理不同的時區,你不再只有日期 - 你總是必須處理完整的日期時間:如果你剝離或放寬時間部分,所有的轉換將不再工作。

關於問題2:UTC時間是通用的,不是基於任何特定的時區,因此一旦您轉換爲UTC,您不必再擔心服務器的時區。

+0

感謝MiMo。看起來我錯過了兩件事。 1.轉換服務器的.ToLocalTime(),2.調整應用程序用戶相對於服務器的時區。如果在同一時區,使用服務器的本地時間,如果在不同的時區,計算差異。 – Liming

+0

@Liming:我擴大了我的答案一點點 – MiMo

+0

MiMo。得到它了!!這解釋了很多。我必須看看TimeZone.ToLocalTime()如何在用戶的瀏覽器中工作。 – Liming

8

如果你想在本地時間在數據庫中存儲爲UTC,你需要先將其轉換爲通用時間:

DateTime dbDateTime = localDateTime.ToUniversalTime(); 
... store dbDateTime in the database ... 

當你從數據庫中讀取回來,它會有它的Kind屬性設置爲未指定。您需要將其Kind屬性明確設置爲UTC:

dbDateTime = ... get from database, e.g. (DateTime) reader["SomeDateTimeColumn"] 
dbDateTime = DateTime.SpecifyKind(dbDateTime, DateTimeKind.Utc); 

然後,如果您想將它轉換爲本地時間,你可以使用:

DateTime localDateTime = dbDateTime.ToLocalTime(); 
+1

我想你假設數據存儲在'datetime'列而不是'datetimeoffset'列上。後者將包含時區偏移量。 – wdosanjos

+0

@wdosanjos,是的,我正在做這個假設。 – Joe

+0

謝謝喬。看起來我錯過了兩件事。 1.轉換服務器的.ToLocalTime(),2.調整應用程序用戶相對於服務器的時區。如果在同一時區,使用服務器的本地時間,如果在不同的時區,計算差異。 – Liming

0

你想要在當地時間存儲日期嗎?如果你只在乎意義何在日期部分,那麼你可能要解析的時間爲UTC其保存到數據庫之前:

DateTime utcDate = DateTime.SpecifyKind(Convert.ToDateTime("7/10/2013"),DateTimeKind.Utc); 

這樣,當它保存到它的已經在UTC數據庫並不包括時間部分。

+0

如何在數據庫SQL Server中保存? ***類型***? 'datetime2'? –

1

我有同樣的問題,我做了以下擴展方法。

public const string UTC = "UTC"; 

    public static DateTime Convert(this DateTime date, string fromZone, string toZone) 
    { 
     TimeZoneInfo to = TimeZoneInfo.FindSystemTimeZoneById(toZone); 
     TimeZoneInfo from = TimeZoneInfo.FindSystemTimeZoneById(fromZone); 
     return new DateTime(TimeZoneInfo.ConvertTime(date, from, to).Ticks, DateTimeKind.Unspecified); 
    } 

    public static bool IsDayLightSaving(this DateTime date, string zone) 
    { 
     TimeZoneInfo to = TimeZoneInfo.FindSystemTimeZoneById(zone); 
     return to.IsDaylightSavingTime(date); 
    } 

    public static DateTime ConvertToUTC(this DateTime date, string fromZone) 
    { 
     return date.Convert(fromZone, DateTime_Extension.UTC); 
    } 

    public static DateTime ConvertToLocal(this DateTime date, string toZone) 
    { 
     return date.Convert(DateTime_Extension.UTC, toZone); 
    } 

我發現的問題實際上是找到當前用戶的時區。由於這是不是在頭中傳遞(你可以通過JavaScript得到它)我已決定要求用戶選擇自己的時區時,他們註冊

希望這有助於

+0

Kevin,非常有用!我假設「fromZone」和「tozone」是像「東部時間」等英語短語? – Liming

+0

對不起,他們是用於區域的字符串。 TimeZoneInfo.GetSystemTimeZones()返回所有時區的列表,如「薩摩亞標準時間」和「太平洋標準時間」等。您只需傳入這些時區即可。 – KevDevMan

+0

基本上我提供一個用戶列表來選擇我從哪個存儲他們的個人資料中使用下面的代碼來呈現選擇列表ReadOnlyCollection tz = TimeZoneInfo.GetSystemTimeZones(); TimeZones = new List (); foreach(TimeZoneInfo tzi in tz) TimeZones.Add(new SelectListItem {Text = tzi.DisplayName,Value = tzi.Id}); } – KevDevMan

0

也許是早上太早我需要另一杯咖啡,但(至少對於展示)不是僅僅使用TimeZoneInfo.ConvertTimeFromUtc並指定用戶所需的TZ的解決方案?或者,ConvertTimeFromUtc沒有考慮轉換回所需TZ的日期/時間?更深層次的思考:即使這樣做,是否有人知道它是否考慮到服務器轉移到DST但用戶期望的TZ尚未完成的邊緣情況?

相關問題