20

将所有内容存储在 GMT 中?

以嵌入偏移量输入的方式存储所有内容?

每次渲染时都要进行数学运算吗?

显示相对时间“1 分钟前”?

4

13 回答 13

38

您必须以 UTC 存储 - 如果您不这样做,那么您在夏令时之类的历史报告和行为会......很有趣。GMT 是本地时间,受制于相对于 UTC 的夏令时(不是)。

如果您要存储本地时间,则向不同时区的用户展示可能是一个真正的混蛋。如果您的原始数据采用 UTC,则很容易调整到本地 - 只需添加用户的偏移量即可!

Joel 在其中一个播客中谈到了这一点(以一种迂回的方式)——他说要尽可能以最高分辨率存储您的数据(搜索“保真度”),因为当它再次消失时,您总是可以对其进行处理。这就是为什么我说将其存储为 UTC,作为当地时间,您需要针对不在该时区的任何人进行调整,这是一项艰巨的工作。并且您需要存储,例如,当您存储时间时,夏令时是否有效。玉。

过去我经常在数据库中存储两个 - UTC 用于排序,本地时间用于显示。这样用户和计算机都不会感到困惑。

现在,至于显示:当然,您可以执行“3 分钟前”的操作,但前提是您存储 UTC - 否则,在不同时区输入的数据将执行诸如显示为“-4 小时前”之类的操作,这将吓坏人。如果您要显示实际时间,人们喜欢在本地时间使用它 - 如果在多个时区输入数据,您只有在存储 UTC 时才能轻松做到这一点。

于 2008-08-15T05:19:37.603 回答
13

一如既往,答案是“取决于”。

这取决于您所描述的时间以及数据是如何提供给您的。决定如何存储时间值的关键是决定是否通过删除时区来丢失信息,以及不要让用户感到惊讶。

在 UTC time_t 中存储数据有一定的好处——它是一个单一的整数,允许快速排序和轻松存储。

我认为问题被分解为特定领域:

  1. 历史数据
  2. 未来,短期数据
  3. 未来的长期数据

每个都有以下子类:

  1. 系统提供
  2. 用户提供

让我们一次看一个。

提供的系统:我建议在 UTC 中运行系统,然后避免时区问题,并且不会出现任何信息丢失(它始终是 UTC)。

历史数据:这些是系统日志文件、进程统计信息、跟踪、评论日期/时间等。数据不会更改,时区描述符不会追溯更改。对于这种类型的数据,无论在哪个时区中提供信息,将信息存储在 UTC 中都不会丢失任何信息。因此,请删除时区。

未来,长期数据:这些事件要么在未来足够远,要么将继续发生。如果它们保持足够长的时间,则时区描述符保证会发生变化。这类数据的一个很好的例子是“每周管理会议”。这是输入一次的数据,并有望永久有效。对于这些值,重要的是确定它是系统提供的还是用户提供的。对于用户提供的数据,时间应该与创建者的时区一起存储,否则会导致信息丢失。当时区定义发生变化并且时间向创建者显示为具有完全不同的值时,这种信息丢失变得明显!

正如 Bwooce 所指出的,创建者和查看者位于不同的时区时存在一些混淆。在这种情况下,我希望应用程序指出哪些时间值由于时区从其先前位置的偏移而发生了移动。

未来,短期数据:这是很快将成为历史的数据,或者仅在短时间内有效。示例可能是间隔计时器、评级转换等。对于这些数据,由于定义在值创建和历史时间之间发生变化的可能性很低,因此可能会放弃时区。但是,我发现这些值有成为“未来,长期数据”的坏习惯。

一旦您决定存储时区,就必须注意它的存储方式。

  • 不要将时区存储为偏移量或完整描述符。

如果您将时区存储为偏移量,如果时区发生变化,您会怎么做?您是否通过系统并对现有数据进行全面更改?如果这样做,那么您现在已经使任何历史值不正确。Oracle 和 iCal 就是这种故障的典型例子。Oracle 将时区信息存储为与 UTC 的偏移量,iCal 包含创建时区的完整描述符。

  • 将其存储为名称。

这允许更改时区的定义,而无需修改您拥有的现有值。它确实使排序更加困难,因为如果时区数据发生变化,生成的任何索引都可能无效。

如果开发人员继续以 UTC 存储所有内容,而不考虑时区,我们将继续看到我们在最后一批时区更改中看到的问题。

在一个组织中,秘书必须在夏令时之前为他们的团队打印日历,然后在更改后再次打印。最后,他们比较了两者并重新创建了所有已移动的约会。当然,他们错过了好几次,而且有好几个星期的痛苦,直到旧的夏令时日期到了,时间又变得正确了。

于 2008-09-25T02:44:22.023 回答
5

乔希在上面是完全正确的,但我有一个微妙的警告要解释。这是一个关于未来事件和时区没有正确答案的案例。

考虑重复约会的情况。它发生在 GMT 0000(为简单起见),即 1200 NZST(新西兰标准时间)和澳大利亚悉尼的 1000 AEST。

当夏令时在一个区域生效时,约会应该发生什么?应该是:

1a。如果 TZ 更改位于约会的“所有者”(预订者)的区域内,那么尝试保持相同的桌面时钟时间(例如上午 10:00)?
1b。如果 TZ 更改位于其他会议参加者的区域之一,则没有更改

后果:由于所有者 TZ 的变化,它出乎意料地为其他所有人移动,但就所有者而言,它仍然是“上午 10 点会议”。

'2。同上,但反过来。

后果:它为会议所有者移动(上午 10 点的会议变成了上午 9 点的会议,或 v/v),这可能是意料之中的,但不方便。在其他与会者完成自己的 TZ 转换之前,它与其他与会者保持相同的桌面时钟时间。

两者都不完美。考虑两个约会的情况,一个由 A 预订,发生在当地时间上午 10 点,另一个由 B 预订,A 参加,发生在上午 9 点。如果 A 人和 B 人在不同的 TZ 中,那么 DST 更改很容易导致他们变成重复预订。

如果你的想法在这一点上有点弯曲,那么我很理解。

此示例背后的要点是,要正确执行这些行为中的任何一个,您不仅需要知道本地时间的 UTC 版本,还需要知道所有者在预订时所在的 TZ(而不是偏移量)。否则,您别无选择,只能默默地选择选项 2,甚至不通知任何人自从格林威治标准时间以来事情已经发生变化并没有改变,只有演示文稿发生变化......对吗?(不,这是陷阱,当您的上午 10 点会议自行进行时,演示文稿很重要)

我必须感谢我的同事和朋友 Jason Pollock 的这一见解。在此处阅读他的观点,以及在此处讨论iCal 和 VTIMEZONE的后续内容。

于 2008-09-25T01:30:01.903 回答
2

以 GMT/UTC 存储所有内容对我来说似乎是最合乎逻辑的。然后,您可以在所需的每个时区显示日期和时间。

一些注意事项:

  1. 如果时间仅被指定为挂钟时间并且这是领先的表示,那么它不是绝对指定的时间。您应该(并且不能)将其转换为任何 GMT 表示形式。每天早上 9:00 AM。换句话说:这不是(日期)时间。
  2. 如果您保存未来约会的日期和时间,您应该使用输入时区和时间本身指定的 GMT 偏移量。因此,如果是夏季预约,例如西欧的冬季,则为 +2:00,尽管正常(冬季时间)偏移量为 +1:00。这将解决 Bwooce 提到的日历问题。
  3. 当然,在转换为 GMT 时使用正确的偏移量同样适用于转换回任何特定时区的日期和时间。

幸运的是,如果使用得当,(.NET)DateTime 类型会为您处理保存日历等所有血腥细节,当您知道它是如何工作时,所有这些都应该非常容易。

于 2009-07-09T14:46:44.473 回答
1

就个人而言,我看不出有任何理由不将所有内容存储在 GMT 中,然后使用用户本地时区来显示与他们相关的时间。

如果您想显示相对时间,您显然仍然需要时间并进行翻译,但如果您确实想要进行翻译,我认为 GMT 仍然是您的最佳选择。

于 2008-08-15T05:05:56.947 回答
1

所以我用 MSSQL 服务器做了一个小实验。

我创建了一个表并添加了一行包含当前本地化时区(澳大利亚)的行。然后我将日期时间更改为 GMT 并添加了另一行。

即使这些行相隔大约 10 秒添加,它们也会出现在 SQL Server 中,因为它们相隔 10 小时。

如果不出意外,它至少告诉我应该以一致的方式存储日期,这对我来说增加了将它们存储为 GMT 的论点的权重。

于 2008-08-15T05:23:13.260 回答
1

MS Dynamics 存储 GMT,然后在用户级别知道您相对于 GMT 的时区。然后它会在您的时区向您显示项目。

只是想我会把它扔在那里,因为那是 MS 的一个相当大的团队,这就是他们决定处理它的方式。

于 2008-08-15T05:27:40.413 回答
1

我更喜欢使用时区存储所有内容。客户可以决定以后应该以哪种方式呈现。我最喜欢的转换库是PostgreSQL-Database

于 2008-10-16T07:13:48.387 回答
1

看看这里,w3c 在回答这个问题方面做得很好。

看看用例。

http://www.w3.org/TR/timezone/

请注意,他们建议将日期时间存储为 UTC 而不是 GMT,GMT 受夏令时限制。

于 2012-09-19T11:18:58.957 回答
0

我喜欢在 GMT 中存储并且只显示相对的(“大约 10 秒前”、“5 个月前”)。对于大多数用例,用户不需要查看实际时间戳。

当然也有例外,一个单独的应用程序可能有很多例外,所以它不能是一个“单向”的答案。需要强大审计能力的事物(例如投票),以及时间是话语领域一部分的系统(天文学、科学研究)可能需要向用户显示真实的时间戳。

但是,大多数应用程序通过简单的相对时间更容易理解。

于 2008-08-15T05:15:29.237 回答
0

我通常只使用 Unix 时间。不一定未来安全,但它运作良好。

于 2008-08-15T06:20:14.160 回答
0

始终以 GMT(或 UTC)存储。从那里很容易转换为任何本地时区值。

于 2008-09-16T20:26:25.987 回答
0

日期应存储为 UTC,除非它是用户提供的数据,并且您无法知道用户希望该数据位于哪个时区。有时(非常非常罕见)您只需要存储小时、分钟、秒、日、月和年没有任何时区的组件,因此您可以将其吐回给用户。现在对于新开发人员或者如果您不确定,请存储 UTC,您将 99% 正确。

但是不要误以为这在所有情况下都 100% 有效。它不是。

于 2019-02-22T20:24:08.567 回答