【问题标题】:How to properly work with Timezone?如何正确使用时区?
【发布时间】:2013-12-26 15:17:01
【问题描述】:

我正在阅读很多关于 timezoneoffsetutclocal time javascript 函数DSTbacon,我正试图将它们组合在一起,为我的应用构建一个可靠/正确的结构。

假设我的应用类似于 StackOverflow。

我就是这样的……

  • 服务器在另一个国家,所以我设置为 UTC 00:00。
  • 我将日期存储为DateTimeOffset
  • 存储TimeZoneID
  • 日期以这种格式发送给客户端:2012-07-19T14:30:00-03:00
  • 我正在使用角度过滤器将其转换为当地时间。

我有几个问题...

1º 服务器时区?

关于我的服务器(单台服务器)...它应该以“中性”UTC (+00:00) 运行吗?如果将来我们搬到一个服务器在不同位置运行的农场怎么办?

2º 我应该存储什么?

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

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

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

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

4º 关于夏令时。

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

【问题讨论】:

  • 你想存储什么?原始时区重要吗? (例如,不同时区的人是否需要查看原始时区?)为什么要存储文化?
  • 不,这不重要。而且这种文化仅用于日期格式。
  • 你不应该让客户确定日期格式吗?如果我(作为英国居民)看到美国用户输入的日期,我仍然希望看到英国格式的日期。
  • 我的英文不太好,所以我想我写的不好理解。但是,文化是我的会话对象的一部分,它是由用户定义的。我将从问题中删除它,因为它并不重要。对此感到抱歉
  • 培根有什么特点??

标签: c# javascript timezone utc datetimeoffset


【解决方案1】:

了解日期/时间的一个非常重要的事情是,没有一种正确的方法可以做所有事情。常见的答案“使用 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。但是很多还是依赖JSDate,所以还是有问题的。 (旁注 - 我正在开发一个 JS 库来解决这个问题,但它还没有准备好分享)。

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

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

#4 - 夏令时

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

从具有偏移量(无论是-03:00 还是Z)通过Date 对象(我相信Angular 过滤器会这样做)的任何值的转换将正确转换为特定的unix 时间戳。

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

【讨论】:

  • 你太棒了!该应用类似于 Stackoverflow。
  • 只要涉及的时间戳是“事件发生的时间”(例如发布时间、评论时间等),那么您可以简单地存储一个 UTC DateTime。时区 ID 不是必需的,因为您不会修改历史记录,并且偏移量没有害处,但也不一定有用。
  • 另请注意,S.O.通过使用“10 分钟前”样式的输出来避免时区转换,并且只显示 UTC 值。此外,他们将积分和其他内容的每日周期基于 UTC 日,这已经被争议为可能不公平 on meta 几次,但这是他们决定的。
  • 我认为可能会改变您使用DateTimeOffset 的一个地方是,如果您想要生成显示人们发布的一天中最活跃时间的统计报告。 UTC 日是一回事,但您可能对更多相对的本地时间段感兴趣,例如“早上”、“中午”、“晚上”、“夜间”。为此,您需要DateTimeOffset 可以提供的“视角”。
  • 这正是我想要的。非常感谢你!您为我节省了几天的测试和搜索时间!先生,你配得上世界上所有的培根。再次感谢您!
【解决方案2】:

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

【讨论】:

  • 使用javascript转换安全吗?
  • @FelipeMiosso,该操作有什么固有的不安全性?
  • @FelipeMiosso 不确定您所说的“安全”是什么意思,但如果您的应用程序是 Web 应用程序,您可以使用 javascript 将 UTC 日期转换为本地时区。见stackoverflow.com/questions/6525538/…
  • stackoverflow.com/questions/2532729/…。也许我误解了这一点,但是......在“不要”部分。据说在客户端处理日期不好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-09
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 2015-09-13
  • 1970-01-01
相关资源
最近更新 更多