如何正确使用Timezone?

时间:2013-12-09 13:31:26

标签: c# javascript timezone utc datetimeoffset

我正在阅读很多关于时区偏移 utc 当地时间 javascript函数 DST 培根我试图将这些结合起来为我的应用构建一个可靠/正确的结构。

假设我的应用程序类似于StackOverflow。

这就是我在做的......

  • 服务器位于其他国家/地区,因此我将其设置为UTC 00:00。
  • 我将日期存储为DateTimeOffset
  • 存储TimeZoneID
  • 日期以此格式发送给客户:2012-07-19T14:30:00-03:00
  • 我正在使用角度过滤器将其转换为当地时间。

我有几个问题......

1º服务器时区?

关于我的服务器(单个服务器)......是否应该使用“中性”UTC(+00:00)运行?如果将来我们迁移到服务器在不同位置运行的服务器场呢?

2º我应该存储什么?

目前,我只将日期存储为DateTimeOffset。我正在阅读关于保存TimeZoneID的内容,但我认为这根本没用。我错过了什么吗?

或者我应该使用DateTimeUtc将日期存储为TimeZoneID,并使用TimeZone类手动转换每个日期?

3º如何转换为当地时间?

在客户端上转换数据是否安全?或者日期转换应该始终在服务器端?

4º关于DST。

使用我目前的方法。 DST会受到尊重吗?

2 个答案:

答案 0 :(得分:7)

了解日期/时间的一个非常重要的事情是,没有一种方法可以做任何事情。常见答案“使用UTC”并不总是适用。上下文非常重要,并且根据您正在使用的值表示的内容有不同的技术和方法。如果您可以详细说明它们在您的应用程序中的用途,我将相应地更新我的答案。与此同时,我将尝试解决你已提出的具体问题:

#1 - 服务器时区

将您的服务器保持在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。虽然它有一点点设计气味,但使用它仍然是“安全的”。

#2 - 存储什么

我建议你阅读我对DateTime vs DateTimeOffset的回答。它应该澄清一些事情。在没有反思整个事情的情况下,重点是虽然两者都准确地代表了一个时间点,但DateTimeOffset提供了视角,而UTC DateTime却没有。

您还询问何时应存储TimeZoneInfo.Id。至少有两种情况需要这样做:

  • 如果您要记录过去或现在的事件,并且您计划允许修改到记录的时间戳。您需要时区来确定新偏移量应该是什么,或者新输入如何转换回UTC。

  • 如果您计划将来有时间,则需要将时区作为重复发生模式的一部分(即使是一次出现)。另请参阅herehere,(对于其他语言,适用相同的原则)。

同样,确切的答案取决于时间戳代表的确切内容。没有一个戒指可以统治它们。

#3 - 客户安全

如果它是.NET客户端,请确保您可以转换它。但我认为您在询问JavaScript客户端浏览器。

“安全”是一个相对术语。如果你要求完全正确,那么不。由于ECMAScript规范中的错误(ES1到ES5.1。它正在为ES6工作),JavaScript并不安全。您可以在我的博客文章中阅读更多内容:JavaScript Date type is horribly broken

但是,如果您正在使用相对较新的数据,并且您的应用程序的用户不属于时区易变的世界的一部分,或者您不需要100%的精确结果,那么您可以“安全地”使用JavaScript转换为用户的本地时区。

对于在JavaScript中实现IANA TZDB的库,您可能会避免某些这些问题,例如我列出的here。但是他们中的许多人仍然依赖于JS Date,所以他们仍然有问题。 (旁注 - 我正在研究一个可以解决这个问题的JS库,但尚未准备好分享)。

服务器端的转换是一个更好的选择,只要您可以询问用户他们的时区。大多数时候,我认为这是可行的。

您可以考虑使用基于地图的时区选择器,例如this onethis one。这两个都需要你使用IANA时区,对于.NET来说意味着使用Noda Time,这无论如何都是一个好主意(恕我直言)。

#4 - 夏令时

使用您当前的方法,DST将在用户为其本地浏览器设置的时区的当前 DST规则的定义中得到尊重。 (再次,请参阅我的博客文章,了解为何会出现这种情况)。

从具有偏移量(-03:00Z)的任何值进行转换,该偏移量通过Date对象(我相信Angular过滤器会执行此操作),将正确转换为特定的unix时间戳。

先前DST规则的DST转换所产生的错误是因为从Date对象内的unix时间戳到本地时区将始终假定当前 DST规则适用,即使时间落入了具有不同规则的时期。

答案 1 :(得分:4)

这实际上取决于您正在编写的实际应用程序,但最简单/最强大的方法IMO是使用UTC存储/计算所有日期,并在显示时将其转换回本地时区它给用户。