9

我在这里的要求是相当标准的;我需要允许用户选择他们当前的时区并将其保存到他们的帐户中。然后,我将使用此值将存储DateTime的值转换为本地时间。

我目前的想法是,我将允许用户从列表中选择一个 .NET TimeZoneInfo.Id(保存在数据库中以允许更友好的描述,但使用 构造TimeZoneInfo.GetSystemTimeZones()) - 然后我将使用此值返回相关TimeZoneInfo实例TimeZoneInfo.FindSystemTimeZoneById()并执行转换。我在这里看到的主要问题是它TimeZoneInfo.Id是注册表中保存的值,而不是“标准”ID(例如,与 Olson 相比)。因此,服务器更新/迁移可能会使存储的 Id 完全无效并破坏转换。

简而言之-这种方法有效/安全吗?如果没有,是否有更好的方法来存储用户时区偏好,同时处理夏令时等,而无需大量额外的逻辑?

4

1 回答 1

9

我刚刚发现了这个古老的未回答的问题,所以我想我应该试一试。

简而言之-这种方法有效/安全吗?

这一切都取决于你打算用它们做什么。

如果您只是在服务器端代码中使用它,那么可以。您只需存储Id时区的 ,并向用户显示相应的DisplayName. FindSystemTimeZoneById并且GetSystemTimeZones对此完全有效。

请记住,虽然Id值始终相同,但DisplayName属性将根据您运行代码的 Windows 操作系统的语言而有所不同。该实现支持文化,因此仅在 .Net 中设置不同的目标文化不会更改DisplayName字符串。

Microsoft Windows 时区数据库中的记录相当稳定,并通过 Windows Update 保持更新。 一些信息来自注册表,但本地化的资源字符串来自tzres.dll. 当然,所有这些都被TimeZoneInfo相关类隐藏起来。

但是,如果您将这些时区Id值传递给其他系统 - 请注意。与以前的 Windows 版本存在一些差异。例如,我知道过去的显示名称都说“GMT”,现在更正确地说是“UTC”。值是相同的Id,但谁知道还有什么不一致。特别是如果目标计算机没有收到与您相同的一组 Windows 更新。顺便说一下,更新在这里公布。

您还应该了解一些有关 Windows 时区数据库的信息:

  • 它不能代表每个日历年超过两个 DST 转换。例如 - 2010 年,埃及开罗有四次转型。微软发布了一个修补程序,但这只是一个妥协的修正,而不是历史上准确的修正。还有其他区域具有这样的历史变化,无法正确表示。

  • Windows XP/2003 和 Vista/2008 之间发生了一些变化。这里有一些非常好的信息,以及关于如何使用注册表的很多细节。

  • 微软是唯一拥有自己时区数据库的主要参与者。世界其他地区使用IANA/Olson 数据库。这会导致互操作性问题。我在时区标签 wiki中有一篇不错的文章。

您还应该知道,它与和类TimeZoneInfo有着千丝万缕的联系。这些都有自己的一套怪癖。 有点用,但充满了细微差别。读:DateTimeDateTimeOffsetDateTimeOffsetDateTime

.Net 中日期和时间的更好解决方案是使用NodaTime。这个库实现了两个时区数据库,包括它们之间的 CLDR 映射。它还提供了一个更安全的 API,不会让您陷入麻烦。这可能需要重新学习,但在不知不觉中,您将使用诸如LocalDateTime、和之类ZonedDateTime的类。OffsetDateTimeInstant

您仍然存在时区数据库经常更新的问题,因为我们将计时规则留给政客。但是TZDB 人员在保持数据库历史准确性方面做得很好,并在区域名称更改时提供别名/链接。您可以在此处查看 tz 名称列表。

此外,如果您使用 NodaTime,您可以选择坚持使用编译到发行版中的 TZDB 副本,或者您可以将自己的副本与您的应用程序一起发布。您可以(理论上)编写自己的代码以从 IANA 下载最新版本并保持应用程序更新——所有这些都无需依赖主机操作系统。

于 2013-05-21T21:42:32.517 回答