2012-09-01 64 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)在修补程序中引入了“北韩标准时间”。 –