我正在阅读很多关于时区,偏移, utc ,当地时间, javascript函数, DST ,培根我试图将这些结合起来为我的应用构建一个可靠/正确的结构。
假设我的应用程序类似于StackOverflow。
这就是我在做的......
DateTimeOffset
。TimeZoneID
。2012-07-19T14:30:00-03:00
。我有几个问题......
关于我的服务器(单个服务器)......是否应该使用“中性”UTC(+00:00)运行?如果将来我们迁移到服务器在不同位置运行的服务器场呢?
目前,我只将日期存储为DateTimeOffset
。我正在阅读关于保存TimeZoneID
的内容,但我认为这根本没用。我错过了什么吗?
或者我应该使用DateTimeUtc
将日期存储为TimeZoneID
,并使用TimeZone
类手动转换每个日期?
在客户端上转换数据是否安全?或者日期转换应该始终在服务器端?
使用我目前的方法。 DST会受到尊重吗?
答案 0 :(得分:7)
了解日期/时间的一个非常重要的事情是,没有一种方法可以做任何事情。常见答案“使用UTC”并不总是适用。上下文非常重要,并且根据您正在使用的值表示的内容有不同的技术和方法。如果您可以详细说明它们在您的应用程序中的用途,我将相应地更新我的答案。与此同时,我将尝试解决你已提出的具体问题:
将您的服务器保持在UTC是最佳做法,而您也可以从Azure或AWS等云提供商那里获得。但这不是你应该依赖的东西。您的服务器应该能够设置为任何时区,而不会影响您的应用程序。只要时钟与NTP服务器同步,时区的选择就无所谓了。
那么你如何确保?很简单,只需确保您的应用程序避免以下所有情况:
DateTime.Now
DateTimeKind.Local
TimeZone
(全班)TimeZoneInfo.Local
DateTime.ToLocalTime()
DateTime.ToUniversalTime()
(因为它假定输入是本地的)TimeZoneInfo.ConvertTimeToUtc(DateTime)
(此特定过载不占用时区,因此它假定为本地时区)另请参阅我的博文:The Case Against DateTime.Now。
请注意,我未在列表中包含DateTimeOffset.Now
。虽然它有一点点设计气味,但使用它仍然是“安全的”。
我建议你阅读我对DateTime vs DateTimeOffset的回答。它应该澄清一些事情。在没有反思整个事情的情况下,重点是虽然两者都准确地代表了一个时间点,但DateTimeOffset
提供了视角,而UTC DateTime
却没有。
您还询问何时应存储TimeZoneInfo.Id
。至少有两种情况需要这样做:
如果您要记录过去或现在的事件,并且您计划允许修改到记录的时间戳。您需要时区来确定新偏移量应该是什么,或者新输入如何转换回UTC。
如果您计划将来有时间,则需要将时区作为重复发生模式的一部分(即使是一次出现)。另请参阅here和here,(对于其他语言,适用相同的原则)。
同样,确切的答案取决于时间戳代表的确切内容。没有一个戒指可以统治它们。
如果它是.NET客户端,请确保您可以转换它。但我认为您在询问JavaScript客户端浏览器。
“安全”是一个相对术语。如果你要求完全正确,那么不。由于ECMAScript规范中的错误(ES1到ES5.1。它正在为ES6工作),JavaScript并不安全。您可以在我的博客文章中阅读更多内容:JavaScript Date type is horribly broken。
但是,如果您正在使用相对较新的数据,并且您的应用程序的用户不属于时区易变的世界的一部分,或者您不需要100%的精确结果,那么您可以“安全地”使用JavaScript转换为用户的本地时区。
对于在JavaScript中实现IANA TZDB的库,您可能会避免某些这些问题,例如我列出的here。但是他们中的许多人仍然依赖于JS Date
,所以他们仍然有问题。 (旁注 - 我正在研究一个可以解决这个问题的JS库,但尚未准备好分享)。
服务器端的转换是一个更好的选择,只要您可以询问用户他们的时区。大多数时候,我认为这是可行的。
您可以考虑使用基于地图的时区选择器,例如this one或this one。这两个都需要你使用IANA时区,对于.NET来说意味着使用Noda Time,这无论如何都是一个好主意(恕我直言)。
使用您当前的方法,DST将在用户为其本地浏览器设置的时区的当前 DST规则的定义中得到尊重。 (再次,请参阅我的博客文章,了解为何会出现这种情况)。
从具有偏移量(-03:00
或Z
)的任何值进行转换,该偏移量通过Date
对象(我相信Angular过滤器会执行此操作),将正确转换为特定的unix时间戳。
先前DST规则的DST转换所产生的错误是因为从Date
对象内的unix时间戳到本地时区将始终假定当前 DST规则适用,即使时间落入了具有不同规则的时期。
答案 1 :(得分:4)
这实际上取决于您正在编写的实际应用程序,但最简单/最强大的方法IMO是使用UTC存储/计算所有日期,并在显示时将其转换回本地时区它给用户。