【问题标题】:Storing a users Time Zone preference存储用户时区首选项
【发布时间】:2012-08-27 05:17:40
【问题描述】:

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

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

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

【问题讨论】:

  • 你看过DateTimeOffset吗?还是NodaTime?
  • @Oded DateTimeOffset 的问题在于它不支持夏令时
  • @Blam - 是的,我很清楚这一点。这就是为什么我也建议NodaTime
  • 如果您想要本地时区,为什么不直接使用 TimeZoneInfo.Local.Id?如果您想从中选择一个列表,可以使用 TimeZoneInfo.GetSystemTimeZones()。

标签: c# .net timezone


【解决方案1】:

我刚刚发现了这个老问题,没有答案,所以我想我应该试一试。

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

这完全取决于您打算如何处理它们。

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

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

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

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

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

  • 它不能代表每个日历年超过两个 DST 转换。例如 - in 2010, Cairo, Egypt had four transitions。微软发布了a hotfix,但这只是做出了妥协的更正,而不是历史上准确的更正。还有其他区域有这样的历史变化,无法正确表示。

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

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

您还应该知道TimeZoneInfoDateTimeDateTimeOffset 类密不可分。这些都有自己的一套怪癖。 DateTimeOffset 有点用处,但DateTime 充满了细微差别。阅读:

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

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

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

【讨论】:

  • 整个 timezoneinfo.ID 的东西没有意义。 ID 应该是遵循某种 ISO 标准方式的标识符。但是,我刚刚发现 FindSystemTimeZoneById 在不同版本的 Windows 中无法正常工作。在一个版本中,返回的字符串都是小写的,而另一个是驼峰式的,更糟糕​​的是,FindSystemTimeZoneById 不区分大小写。去图吧!
  • @Rajiv - 时区没有 ISO 标准。 IANA/Olson 标识符(如上所述)是我们拥有的最接近标准的东西。关于 Windows ID,我从来没有遇到过小写的,除非它们被其他东西弄坏了。如上所述,ID 应该跨系统保持一致,除非您谈论的是新引入的时区,该时区已安装在一个系统上,但未安装在另一个系统上。例如,KB3093504 在修补程序中引入了“朝鲜标准时间”。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-07
相关资源
最近更新 更多