2012-09-01 93 views
5

這裏我的要求是相當標準的;我需要允許用戶選擇他們當前的時區並將其保存在他們的賬戶中。然後我將使用此值將存儲的DateTime值轉換爲本地時間。我現在的想法是,我將允許用戶從列表中選擇一個.NET TimeZoneInfo.Id(保留在DB中以允許更友好的描述,但使用TimeZoneInfo.GetSystemTimeZones()構造) - 然後,我將使用此值返回相關的TimeZoneInfo實例使用TimeZoneInfo.FindSystemTimeZoneById()並執行轉換。我在這裏看到的主要問題是TimeZoneInfo.Id是在註冊表中保存的值,不是「標準」Id(與Olson相比)。因此,有可能是服務器的更新/遷移可能完全無效存儲的ID和打破轉換..存儲用戶時區首選項

總之 - 是這種方法有效/安全嗎?如果沒有,是否有更好的方式來存儲用戶時區偏好,同時還可以在不需要大量附加邏輯的情況下處理夏令時等等?

+0

你看過['DateTimeOffset'](http://msdn.microsoft.com/en-us/library/system.datetimeoffset.aspx)嗎?或['NodaTime'](http://code.google.com/p/noda-time/)? – Oded

+0

相關:http://stackoverflow.com/q/2532729/1583 – Oded

+1

@Oded與DateTimeOffset的問題是,它不是日光節約知道 – Paparazzi

回答

8

我剛剛發現這個老十歲上下的懸而未決的問題,所以認爲我應該在它採取刺傷。

總之 - 是這種方法有效/安全嗎?

這一切都取決於你打算用他們做什麼。

如果你只是在服務器端代碼中使用它,那麼是的。您只需存儲時區的Id,並向用戶顯示相應的DisplayNameFindSystemTimeZoneByIdGetSystemTimeZones對此完全有效。

請記住,雖然Id值總是一樣的 - DisplayName屬性將根據您正在運行的代碼的Windows操作系統的語言是不同的。執行是而不是文化意識,所以只需在.Net中設置不同的目標文化將不會更改DisplayName字符串。

在Microsoft Windows時區數據庫中的記錄是相當穩定,並保持通過Windows Update更新。 某些的信息來自注冊表,但本地化的資源字符串來自tzres.dll。當然,所有這些都是由TimeZoneInfo和相關類隱藏的。

但是,如果你路過這些時區Id值與其它系統 - 當心。與以前版本的Windows有一些變化。例如,我知道用於顯示名稱的顯示名稱都在其中,現在更正確地說「UTC」。 Id值是相同的,但是誰確切地知道還有哪些不一致。特別是如果目標計算機尚未收到您擁有的同一組Windows Update。順便說一句 - 更新公佈here

你也應該知道有關Windows時區數據庫中的幾件事情:

  • 它不能代表每個日曆年超過兩個DST轉換。例如 - in 2010, Cairo, Egypt had four transitions。微軟發佈a hotfix,但這只是一個妥協糾正,而不是歷史上的準確。還有其他的區域有這樣的歷史變化,無法正確表示。

  • 在Windows XP/2003和Vista/2008之間發生了一些變化。關於這個here有一些非常好的信息,以及關於如何使用註冊表的很多細節。

  • 微軟是只有主要播放器與他們自己的時區數據庫。世界其他地方使用IANA/Olson database。這導致互操作性問題。我在the timezone tag wiki有一個像樣的寫法。

你也應該知道,TimeZoneInfo是密不可分的DateTimeDateTimeOffset類。這些都有他們自己的怪癖。 DateTimeOffset有點用處,但DateTime充滿了細微差別。閱讀:

一個更好的解決日期和時間在.NET是使用NodaTime。該庫實現了兩個時區數據庫,包括它們之間的CLDR映射。它還提供了一個更安全的API,不會讓你陷入困境。這可能需要一些重新學習,但在您知道之前,您將使用類如LocalDateTime,ZonedDateTime,OffsetDateTimeInstant

您仍然有時區數據庫經常更新的問題,因爲我們將計時規則留給政客。但the TZDB folks在保持歷史數據庫準確性方面做得非常好,並且在區域名稱更改時提供別名/鏈接。您可以看到tz名稱here的列表。此外,如果您使用NodaTime,則可以選擇將TZDB的副本粘貼到發行版中,也可以將自己的副本隨應用程序一起發送。您可以(理論上)編寫您自己的代碼,從IANA下載最新版本並保持應用程序更新 - 所有這些都不依賴於主機操作系統。

+0

整個timezoneinfo.ID的東西沒有任何意義。預計該ID將成爲遵循某種ISO標準方式的標識符。但是,我發現'FindSystemTimeZoneById'在不同版本的Windows中無法正常工作。在一個版本中,返回的字符串全部小寫,而另一個則是駱駝大小寫,並且使事情變得更糟,FindSystemTimeZoneById不區分大小寫。去搞清楚! – Rajiv

+0

@Rajiv - 時區沒有ISO標準。 IANA/Olson標識符(如上所述)是我們最接近標準的東西。關於Windows ID,我從來沒有遇到過任何小事,除非他們被別的東西弄壞了。如上所述,除非您正在討論已在一個系統上安裝但不是另一個系統上新引入的時區,否則這些ID在系統中應該保持一致。例如,[KB3093504](https://support.microsoft.com/zh-cn/kb/3093503)在修補程序中引入了「北韓標準時間」。 –