我在这里的要求是相当标准的;我需要允许用户选择他们当前的TimeZone并将其保存到他们的帐户中。然后,我将使用该值将存储的DateTime
值转换为本地化时间。
我当前的想法是,我将允许用户从列表中选择一个.NET TimeZoneInfo.Id
(保留在数据库中,以便进行更友好的描述,但使用TimeZoneInfo.GetSystemTimeZones()
构造)-然后,我将使用该值使用TimeZoneInfo
返回相关的TimeZoneInfo.FindSystemTimeZoneById()
实例并执行转换。我在这里看到的主要问题是TimeZoneInfo.Id
是注册表中保存的一个值,而不是“标准” ID(例如,与Olson相比)。因此,服务器更新/迁移可能会完全使存储的ID无效并使转换中断。
简而言之-这种方法有效/安全吗?如果不是,是否有更好的方法来存储用户的时区首选项,同时还处理夏时制等,而又不增加大量逻辑?
最佳答案
我刚刚发现了这个古老的 Unresolved 问题,因此以为我应该对它进行刺探。
In short - is this approach valid/safe?
这完全取决于您打算如何处理它们。
如果仅在服务器端代码中使用它,则可以。您只需存储时区的
Id
,然后向用户显示相应的DisplayName
。 FindSystemTimeZoneById
和GetSystemTimeZones
对此完全有效。请记住,尽管
Id
值始终相同,但DisplayName
属性将根据运行代码的Windows操作系统的语言而有所不同。该实现不了解区域性,因此仅在.Net中设置不同的目标区域性就不会更改DisplayName
字符串。Microsoft Windows时区数据库中的记录相当稳定,并通过Windows Update进行更新。一些信息来自注册表,但是本地化的资源字符串来自
tzres.dll
。当然,TimeZoneInfo
和相关类对您隐藏了所有这些内容。但是,如果要将这些时区
Id
值传递给其他系统,请当心。 Windows的早期版本有一些变体。例如,我知道以前所有显示名称都用“GMT”表示,现在更正确地用“UTC”表示。 Id
的值是相同的,但谁能确切知道还有哪些不一致。特别是如果目标计算机没有收到与您拥有的Windows Updates相同的一组Windows Updates。顺便说一句-更新宣布here。您还应该了解有关Windows时区数据库的一些知识:
您还应该知道
TimeZoneInfo
与DateTime
和DateTimeOffset
类有着千丝万缕的联系。这些有他们自己的一套怪癖。 DateTimeOffset
有点可用,但是DateTime
充满了细微差别。读:Jon Skeet的
.Net中日期和时间的更好解决方案是使用NodaTime。该库实现了两个时区数据库,包括它们之间的CLDR映射。它还提供了更安全的API,不会让您遇到麻烦。可能需要重新学习一点,但是在您不了解之前,您将使用
LocalDateTime
,ZonedDateTime
,OffsetDateTime
和Instant
这样的类。您仍然存在时区数据库经常更新的问题,因为我们将计时规则留给政客。但是the TZDB folks很好地保持了数据库的历史准确性,并在区域名称更改时提供别名/链接。您可以看到tz名称here的列表。
另外,如果您使用NodaTime,则可以选择保留编译到发行版中的TZDB副本,也可以将自己的副本随应用程序一起提供。您可以(理论上)编写自己的代码以从IANA下拉最新版本并保持应用程序更新-所有这些都无需依赖主机操作系统。
关于c# - 存储用户的时区首选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12231422/