存储DateTime(UTC)与存储DateTimeOffset的区别

108

我通常会有一个“拦截器”,在读写数据库之前进行日期时间转换(从UTC到本地时间,从本地时间到UTC),这样我就可以在整个系统中使用 DateTime.Now(派生和比较)而不必担心时区。

关于序列化和在计算机之间移动数据,无需担心,因为日期时间始终是UTC时间。

我应该继续以UTC格式存储我的日期(SQL 2008 - datetime),还是应该改用 DateTimeOffset 存储(SQL 2008 - datetimeoffset)?

在数据库中使用UTC日期(datetime类型)已经运作良好并且已知很长时间,为什么要改变呢?有什么优点吗?

我已经看过像这篇文章那样的文章,但我并不完全相信。你有什么想法吗?


相关问题:https://dev59.com/U3E85IYBdhLWcg3w8IbK - Oded
1
参见:DateTime vs DateTimeOffset - 该文章是针对.Net编写的,但概念上也适用于SQL。 - Matt Johnson-Pint
3个回答

148

有一个重大的区别,您不能仅使用UTC。

  • 如果您有这样的情况

    • 一个服务器几个客户端(所有地理位置位于不同时区
    • 客户端创建具有日期时间信息的一些数据
    • 客户端将其全部存储在中央服务器上
  • 然后:

    • datetimeoffset存储客户端的本地时间和偏移量到UTC时间
    • 所有客户端都知道所有数据的UTC时间以及信息来源地的当地时间
  • 但是:

    • UTC datetime仅存储UTC datetime,因此您没有关于数据源客户端位置的本地时间信息
    • 其他客户端不知道日期时间信息来自何处的本地时间
    • 其他客户端只能从数据库计算出其本地时间(使用UTC时间),而不是数据源客户端的本地时间

简单的例子是航班预订系统... 航班票应包含两个时间: -“起飞”时间(在“出发城市”的时区) -“降落”时间(在“目的地城市”的时区)


3
这是我读过的关于何时适用最好的解释,我读了很多。但对我们来说似乎不是这样。我们获取外部数据的时间是以协调世界时(UTC)为基准,并且如果需要(实际上从未需要过),我们可以从另一个来源得知位置。感谢您让它看起来如此明显。 - Andrew
22
你说过“datetimeoffset 存储了UTC时间和客户端本地时间的偏移量”,但实际上 datetimeoffset 存储的是本地时间加上偏移量,或者是UTC时间加上偏移量等于+0。 - Serhii Kyslyi
虽然您可以将DTO转换为DT,因为DT基于UTC(尽管这对使用数据库的每个人来说都是额外的步骤,并且可以认为并不比仅使用UTC时间更简单) - John Smith
2
似乎更像是DateTimeOffset存储的是“本地时间和UTC偏移量”,而不是“UTC时间和UTC偏移量”。如果你强制转换为datetime或使用任何日期部分函数,你会得到本地日期和时间组件。 - Triynko
所有客户端都知道所有数据的UTC时间以及信息来源地点的本地时间,尽管在这种情况下将其存储为日期字段的一部分可能会使其非规范化。那么使用示例是什么,也就是说,为什么不使用UTC并提取偏移量到“InputLocationId”(或类似的规范实体)?虽然会涉及计算(你好,例外…特别是印第安纳州),但这仍然是一个确定性的过程 - 然后应用程序的日期时间逻辑的平衡是直截了当的。 - ruffin
谢谢 @SerhiiKyslyi 和 Triynko,当然是本地时间 + 偏移,而不是 UTC + 偏移。 - Marcel Toth

26
你在使用UTC记录历史事件时是完全正确的。可以从UTC转换成本地时间,但反过来不一定成立。
何时使用本地时间?回答以下问题:
如果政府突然决定更改夏令时,您希望这些数据随之更改吗?
只有回答“是”,才存储本地时间。显然,这只适用于未来日期,并且通常仅适用于以某种方式影响人们的日期。
为什么要存储时区/偏移量?
首先,如果要记录执行操作的用户的偏移量,最好直接这样做,即在登录时记录该用户的位置和时区。
其次,如果要进行显示转换,需要拥有该时区所有本地时间偏移量转换的表,仅知道当前偏移量是不够的,因为如果您正在显示六个月前的日期/时间,则偏移量将不同。

4
Windows UTC 到本地时间的转换会考虑历史日期的夏令时更改。在这种情况下,我不明白为什么你想要存储本地时间。 - jamiegs
1
@Jamiegs 在历史上,Windows 只知道“最后的历史信息”(如 .NET DateTime 文档中所暗示/注明)。它并不全面。 - user166390
2
当然,你也必须存储事件的位置,否则你无法说明事件发生的“本地时间”。 - keuleJ

21

DATETIMEOFFSET可以让你在一个字段中存储本地时间和UTC时间。

这样可以非常简单、高效地在本地或UTC时间生成报告,而不需要对数据进行任何显示处理。

这是两个最常见的需求——本地报告需要本地时间,组报告需要UTC时间。

本地时间存储在DATETIMEOFFSET的DATETIME部分,UTC与本地时间偏移量则存储在OFFSET部分,因此转换非常简单。由于不需要了解数据来自哪个时区,因此所有转换都可以在数据库级别完成。

如果您不需要精确到毫秒的时间,例如只需要精确到分钟或秒钟,则可以使用DATETIMEOFFSET(0)。 DATETIMEOFFSET字段将仅需要8个字节的存储空间,与DATETIME相同。

因此,使用DATETIMEOFFSET而不是UTC DATETIME可为报告提供更多灵活性、效率和简易性。


很遗憾,实体框架没有任何方法可以访问datetimeoffset字段的本地日期时间,这使得查询特定的本地日期变得不可能。 - Triynko
@Triynko,你能解释一下你的意思吗?有例子吗? - reidLinden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接