处理存储中的时区?
Posted
技术标签:
【中文标题】处理存储中的时区?【英文标题】:Handling timezones in storage? 【发布时间】:2010-09-05 22:24:40 【问题描述】:在 GMT 中存储所有内容?
以嵌入偏移量输入的方式存储所有内容?
每次渲染时都要计算一下吗?
显示相对时间“1 分钟前”?
【问题讨论】:
【参考方案1】:就个人而言,我看不出有什么理由不将所有内容存储在 GMT 中,然后使用用户本地时区来显示与他们相关的时间。
如果您想显示相对时间,显然您仍然需要时间并进行翻译,但如果您确实想进行翻译,我认为 GMT 仍然是您的最佳选择。
【讨论】:
问题是,自动化流程在与人们沟通(例如,截止日期)时使用什么时间?您是否按照用户的决定存储时区并在所有通信中使用它?【参考方案2】:我喜欢在 GMT 中存储并且只显示相对的(“大约 10 秒前”、“5 个月前”)。对于大多数用例,用户不需要查看实际时间戳。
当然也有例外,一个单独的应用程序可能有很多例外,所以它不能是一个“唯一正确”的答案。需要强大审计能力的事物(例如投票),以及时间是话语领域一部分的系统(天文学、科学研究)可能需要向用户显示真实的时间戳。
不过,大多数应用通过简单的相对时间更容易理解。
【讨论】:
【参考方案3】:您必须以 UTC 格式存储 - 如果您不这样做,您在夏令时之类的历史报告和行为会变得......很有趣。 GMT 是本地时间,受制于相对于 UTC 的夏令时(不是)。
如果您要存储本地时间,那么向不同时区的用户演示可能会是一个真正的混蛋。如果您的原始数据采用 UTC,则很容易调整到本地 - 只需添加用户的偏移量即可!
Joel 在其中一个播客中谈到了这一点(以一种迂回的方式) - 他对 store your data in the highest resolution possible 说(搜索“保真度”),因为当它再次消失时,你总是可以将其删除。这就是为什么我说将其存储为 UTC,作为当地时间,您需要针对不在该时区的任何人进行调整,这是一项艰巨的工作。并且您需要存储,例如,当您存储时间时,夏令时是否有效。呵呵。
过去我经常在数据库中存储两个 - UTC 用于排序,本地时间用于显示。这样用户和计算机都不会感到困惑。
现在,至于显示:当然,您可以执行“3 分钟前”的操作,但前提是您存储 UTC - 否则,在不同时区输入的数据会显示为“-4 小时前” ,这会吓坏人们。如果您要显示实际时间,人们喜欢在本地时间使用它 - 如果要在多个时区输入数据,您只有在存储 UTC 时才能轻松做到这一点。
【讨论】:
但是,假设您有一个预订系统,并且您在 DST 下午 3 点的时区预订了房间。当 DST 发生时,GMT 和会议室时区之间的偏移会改变一小时。突然,会议在不同的时间被预订了! 没关系,我没想到你会将时间转换为会议发生那一刻的 DST 偏移量,所以它总是在正确的偏移量中。 不,GMT 没有夏令时。如果我们是迂腐的,那么 UTC 也不是时区。格林威治标准时间基于格林威治的平均太阳时。 UTC 基于原子时间 (TAI) 调整整数秒(想想闰秒)以保持接近地球的太阳阶段,尽管它们最多可以相差 0.9 秒。要让地球的自转时间发生明显的变化,你必须保持相见好几年,但这就是复杂性存在的原因。【参考方案4】:所以我用 MSSQL 服务器做了一个小实验。
我创建了一个表格并添加了一行包含当前本地化时区(澳大利亚)的行。 然后我将日期时间更改为 GMT 并添加了另一行。
即使这些行是相隔大约 10 秒添加的,但它们在 SQL Server 中显示的时间却是相隔 10 小时。
如果不出意外,它至少告诉我应该以一致的方式存储日期,这对我来说增加了将它们存储为 GMT 的论点。
【讨论】:
用嵌入的偏移量存储它们,也可能意味着 2 列、gmt 时间和人选择的偏移量,而不是自动化的一种形式的 sqlserver 或客户端机器。【参考方案5】:MS Dynamics 存储 GMT,然后在用户级别知道您相对于 GMT 的时区。然后它会在您的时区向您显示项目。
我只是想把它扔出去,因为那是 MS 的一个相当大的团队,这就是他们决定处理它的方式。
【讨论】:
【参考方案6】:我通常只使用 Unix 时间。不一定未来安全,但效果很好。
【讨论】:
【参考方案7】:始终以 GMT(或 UTC)存储。从那里可以很容易地转换为任何本地时区值。
【讨论】:
【参考方案8】:上面的 Josh 完全正确,但我需要解释一个微妙的警告。这是一个关于未来事件和时区没有正确答案的案例。
考虑重复约会的情况。它发生在 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,甚至不通知任何人自从 GMT 时间以来事情发生了变化,并没有改变,只有演示文稿发生了变化……对吗? (不,这是陷阱,当您的上午 10 点会议自行进行时,演示很重要)
我必须感谢我的同事和朋友 Jason Pollock 的这一见解。阅读his view here,并在此处后续讨论iCal and VTIMEZONE。
【讨论】:
Outlook Mobile 被这个行为错误弄糊涂了。当我更改活动区域时,电话预约会发生变化。 @devstuff - 当您选择不同的时区时,约会发生变化并不是所描述的。所描述的是时区本身已经改变(由于夏令时的立法变化),因此最初描述数据的时区不再存在。即时间在同一个时区发生了变化。【参考方案9】:一如既往,答案是“取决于”。
这取决于您所描述的时间以及数据是如何提供给您的。 决定如何存储时间值的关键是确定您是否会因删除时区而丢失信息,以及是否让您的用户感到惊讶。
在 UTC time_t 中存储数据有一定的好处 - 它是一个单一的 int,允许快速排序和轻松存储。
我认为问题被分解为特定领域:
-
历史数据
未来,短期数据
未来的长期数据
每个都有以下子类:
-
系统提供
用户提供
让我们一次看一个。
系统提供:我建议在 UTC 中运行系统,这样您就可以避免时区问题,而且不会出现任何信息丢失(始终是 UTC)。
历史数据:这些是系统日志文件、进程统计信息、跟踪、评论日期/时间等。数据不会改变,时区描述符也不会改变追溯更改。对于这种类型的数据,将信息存储在 UTC 中不会丢失任何信息,无论提供的时区如何。因此,请删除时区。
未来、长期数据:这些事件要么在未来足够远,要么将继续发生。如果它们保持足够长的时间,则时区描述符保证会发生变化。这类数据的一个很好的例子是“每周管理会议”。这是输入一次的数据,并有望永久有效。对于这些值,重要的是确定它是系统提供的还是用户提供的。对于用户提供的数据,时间应与创建者的时区一起存储,否则会导致信息丢失。当时区定义发生变化并且时间向创建者显示为具有完全不同的值时,这种信息丢失变得明显!
正如 Bwooce 所指出的,在创建者和查看者位于不同时区的情况下存在一些混淆。在这种情况下,我希望应用程序能够指出哪些时间值由于与之前位置的时区偏移而发生了移动。
未来、短期数据:这些数据很快就会成为历史数据,或者仅在短时间内有效。示例可能是间隔计时器、评级转换等。对于这些数据,由于定义在值创建和历史时间之间发生变化的可能性很低,因此可以通过删除时区来侥幸逃脱。但是,我发现这些值有成为“未来、长期数据”的坏习惯。
一旦您决定存储时区,就必须注意它的存储方式。
不要将时区存储为偏移量或完整描述符。如果您将时区存储为偏移量,如果时区发生变化,您会怎么做?您是否通过系统并对现有数据进行全面更改?如果这样做,那么您现在已经使任何历史值不正确。 Oracle 和 iCal 就是这种故障的典型例子。 Oracle 将时区信息存储为与 UTC 的偏移量,iCal 包含创建时区的完整描述符。
请将其存储为名称。这允许更改时区的定义,而无需修改您拥有的现有值。它确实使排序更加困难,因为如果时区数据发生变化,生成的任何索引都可能无效。
如果开发人员继续以 UTC 存储所有内容,而不考虑时区,我们将继续看到我们在上一批时区更改中看到的问题。
在一个组织中,秘书必须在夏令时之前为他们的团队打印日历,然后在更改后再次打印。最后,他们比较了两者并重新创建了所有已移动的约会。当然,他们错过了好几个,并且在到达旧的夏令时日期并且时间再次正确之前,有几个星期的痛苦。
【讨论】:
【参考方案10】:我更喜欢使用时区存储所有内容。 客户可以决定以后应该以哪种方式呈现。 我最喜欢的转换库是PostgreSQL-Database。
【讨论】:
【参考方案11】:在 GMT/UTC 中存储所有内容对我来说似乎是最合乎逻辑的。然后,您可以在所需的每个时区显示日期和时间。
一些注意事项:
-
如果时间仅指定为
挂钟时间,这就是
领先的代表,那么它是
不是绝对指定的时间。
您应该(并且不能)转换它
在任何 GMT 表示中。例如。 9:00
每天早上早上。换一种说法:
这不是(日期)时间。
如果你
保存未来的日期和时间
约会,你应该使用
输入指定的 GMT 偏移量
时区和时刻
本身。所以如果是约会
夏天在冬天制造,例如
西欧,+2:00,
尽管正常(冬季)
偏移量为 +1:00。这将解决
Bwooce 的日历问题
提及。
当然一样
适用于使用权利
转换为 GMT 时的偏移量
转换回时适用
任何特定的日期和时间
时区。
幸运的是,如果使用得当,(.NET) DateTime 类型会为您处理保存日历等所有血腥细节,当您知道它是如何工作时,所有这些都应该非常容易。
【讨论】:
【参考方案12】:看看这里,w3c 在回答这个问题方面做得非常出色。
查看用例。
http://www.w3.org/TR/timezone/
请注意,他们建议将日期时间存储为 UTC 而不是 GMT,GMT 受夏令时限制。
【讨论】:
【参考方案13】:日期应存储为 UTC,除非它是用户提供的数据,并且您不知道用户希望该数据处于哪个时区。有时(非常罕见)您只需要存储小时、分钟、秒、日、没有任何时区的月份和年份组件,因此您可以将其吐回给用户。现在对于新开发人员或者如果您不确定,请存储 UTC,您将 99% 正确。
但不要误以为这在所有情况下都 100% 有效。它没有。
【讨论】:
以上是关于处理存储中的时区?的主要内容,如果未能解决你的问题,请参考以下文章