关于日期:以UTC格式存储时间总是一个好主意,还是在本地时间存储更好?

Is it always a good idea to store time in UTC or is this the case where storing in local time is better?

一般来说,最好将时间存储在UTC中,如这里和这里所述。

假设有一个正在发生的事件,比如说结束时间,它总是在同一个本地时间,比如17:00,不管该时区是否有夏令时。此外,当特定时区的DST打开或关闭时,也要求不要手动更改时间。它还要求任何其他系统通过API(即GetEndTimeByEvent)请求结束时间时,始终以UTC格式发送结束时间。

方法1:如果决定将其存储在UTC中,则可以将其存储在下面的数据库表中。

1
2
3
4
5
Event      UTCEndTime
=====================
ABC         07:00:00
MNO         06:00:00
PQR         04:00:00

对于第一个事件abc,UTC中的结束时间为07:00 am,如果在2012年7月1日转换为从UTC显示为本地时间,则会导致当地时间为17:00;如果在2012年10月10日(时区的DST打开日期)转换,则会导致下午6点,这是不正确的结束时间。

我认为一种可能的方法是将DST时间存储在附加列中,并在时区打开DST时使用该时间。

方法2:但是,如果它存储为以下本地时间,例如事件ABC,则在任何日期都将始终为17:00,因为没有从UTC到本地时间的转换。

1
2
3
4
5
Event      LocalEndTime
=======================
ABC         17:00:00
MNO         16:00:00
PQR         14:00:00

应用层将本地时间转换为UTC时间,通过(api getendtimebyevent)发送到其他系统。

在这种情况下,用UTC存储时间仍然是一个好主意吗?如果是,那么如何获得恒定的本地时间?

相关问题:有没有一个好的理由来存储时间而不是用UTC?


我认为为了回答这个问题,我们应该考虑使用UTC存储时间戳的好处。

我个人认为,这样做的主要好处是,时间总是(大部分)被保证是一致的。换言之,无论何时时区更改或DST应用,您都不会及时返回或返回。这在文件系统、日志等中特别有用。但是在你的申请中有必要吗?

想想两件事。首先,关于DST时钟移位的时间。您的活动是否有可能在凌晨2点到3点之间发生(在下班时间)?那会发生什么?

其次,申请是否会受到实际时区变化的影响?换言之,你是否打算带着它从伦敦飞往华沙,并适当地改变你的电脑时区?在这种情况下会发生什么?

如果你对这两个问题都回答"不",那么你在当地时间就更好了。它将使您的应用程序更简单。但如果你至少回答过一次"是",我想你应该多考虑一下。

这就是数据库。另一件事是应用程序内部使用的时间格式,这应该取决于您实际将用该时间做什么。

您提到过它通过API公开时间。应用程序会在每次请求时查询数据库吗?如果在内部将时间存储为UTC,则需要这样做,或者确保在DST/TimeZone更改时,将调整/修剪缓存的时间。

它会对时间本身有什么影响吗?像打印一样,事件将在8小时内发生,或者在大约8小时内暂停?如果是,那么UTC可能会更好。当然,你需要考虑所有的前题。


我喜欢这样想:

计算机不关心时间作为人类可以理解的表现形式。他们不关心时区、日期和时间字符串格式或任何这些。只有人类才关心如何解释和表示时间。

让数据库做它擅长的事情:将时间存储为一个数字——一个unix epoch(1970-01-01以来经过的秒数)或一个UTC时间戳(没有时区或夏令时信息)。只有当你必须的时候,才关心你自己用一种人类可以理解的方式来代表时间。这意味着在应用程序逻辑、报告系统、控制台应用程序或任何其他地方,都会有人查看数据。


以下内容不适用于真正的多租户全球SaaS产品,因此这一观点针对的是简单的"业务线"应用程序开发人员。

存储为UTC是可以的,但是如果这样做,有一个要求会导致疼痛:"你能给我写一份报告,告诉我每天发生多少次X吗?"

如果您将日期存储为UTC,则此要求将导致痛苦;您需要在应用程序服务器和报告中编写时区调整代码;您对包含日期条件的数据执行的每个即席查询都需要考虑到这一点。

如果您的申请符合以下条件:

  • 每个实例都基于一个时区。
  • 时区转换通常不在办公时间内,或者您不太关心事情的"持续时间",而将时间缩短到一个小时左右是很重要的。
  • 我建议您将日期时间存储为本地日期时间,同时使用将您与服务器时区配置问题隔离的库(例如.NET世界中的noda.time)。


    如果您的系统间消息使用ISO 8601,并且您的数据库正在存储原点本地时间+偏移(如在Mongo中的EDCOX1 OR 0或EDCOX1×1),ISO 8601捕获它,并且您只使用EDCOX1在.NET或EDCOX1中3个引用,或在代码中的一些等价物,则根本不需要转换。你只要把它存起来。所有的比较函数都可以工作。

    如果您在持久性中转换为UTC,那么您就失去了从用户角度出发的偏移量。十年前当你的用户签署了一个文档时显示现在是一个难题。从联合技术公司得出这一结论意味着要查找当时在该地区正在使用的DST规则。噩梦。

    我相信我们之所以如此习惯于转换为UTC以实现持久性,是因为我们从未使用过正确的数据结构/数据类型来允许我们做正确的事情。


    我只存储时间组件,没有任何区域。每当API必须为其提供服务时,请添加正确的日期,并将其作为本地时间转换为该日期的UTC。

    数据库=17:00(使用不带日期的时间戳,小时为字节,分钟为字节,字符串)

    retrieve=我们想要事件的日期+数据库17:00=>将其从本地转换为UTC

    这样,您将始终以UTC格式提供正确的时间。


    实际上,您并不像大多数时间API假定的那样存储特定的时间点。如果数据库支持间隔(PostgreSQL支持),请使用间隔,或将其存储为整数,表示从午夜开始的秒数(分钟/小时)或计划的相应开始时间(星期一、月的第一个月等)。在这两种情况下,您都已经摆脱了许多困扰,担心系统之间如何处理"时间",并且在您的视图中只增加了一个非常小的头痛,即将秒转换为一天中的时间。