以 UTC 存储时间总是一个好主意,还是以本地时间存储更好?
Posted
技术标签:
【中文标题】以 UTC 存储时间总是一个好主意,还是以本地时间存储更好?【英文标题】:Is it always a good idea to store time in UTC or is this the case where storing in local time is better? 【发布时间】:2012-07-17 05:40:48 【问题描述】:一般来说,最好的做法是使用 UTC 存储时间,如 here 和 here 中所述。
假设有一个重复发生的事件,假设结束时间始终与当地时间相同,假设为 17:00,无论该时区是否开启或关闭夏令时。并且还要求在特定时区的 DST 打开或关闭时不要手动更改时间。还要求任何其他系统通过 API(即 GetEndTimeByEvent)询问结束时间时始终以 UTC 格式发送结束时间。
方法一: 如果决定以 UTC 存储,则可以将其存储在数据库表中,如下所示。
Event UTCEndTime
=====================
ABC 07:00:00
MNO 06:00:00
PQR 04:00:00
对于第一个事件 ABC,UTC 的结束时间是上午 07:00,如果转换为 2012 年 7 月 1 日从 UTC 显示为本地时间,它将导致本地时间 17:00,如果转换为 10 月 10 日-2012(时区 DST 开启的日期)将导致下午 6 点,这不是正确的结束时间。
我能想到的一种可能方法是将夏令时时间存储在附加列中,并在时区开启夏令时时使用该时间。
方法二: 但是,如果它存储为本地时间,例如对于事件 ABC,它在任何日期将始终为 17:00,因为没有从 UTC 转换为本地时间。
Event LocalEndTime
=======================
ABC 17:00:00
MNO 16:00:00
PQR 14:00:00
应用层将本地时间转换为UTC时间,通过(API GetEndTimeByEvent)发送给其他系统。
在这种情况下,以 UTC 格式存储时间仍然是个好主意吗?如果是,那么如何获得恒定的当地时间?
相关问题:Is there ever a good reason to store time not in UTC?
【问题讨论】:
程序是否只用于此类事件?它是否需要为 DST 更改时发生的事件提供服务?程序是否应该处理不断变化的时区? @Michal 是的,所有事件始终是特定本地时区的本地时间(即下午 4 点或晚上 9 点等),无论 DST 是打开还是关闭。假设特定事件“MNO”在伦敦当地时间每天下午 4 点发生,无论 DST 是打开还是关闭。 【参考方案1】:我认为,为了回答这个问题,我们应该考虑使用 UTC 存储时间戳的好处。
我个人认为这样做的主要好处是时间总是(大部分)保证一致。换句话说,无论何时更改时区或应用 DST,您都不会及时返回或返回。这在文件系统、日志等中特别有用。但它在您的应用程序中有必要吗?
想两件事。首先,关于夏令时时钟移位的时间。您的活动是否有可能发生在凌晨 2 点到凌晨 3 点之间(在时钟轮班结束的那一天)?那应该怎么办?
其次,应用程序是否会受到实际时区变化的影响?换句话说,你打算带着它从伦敦飞到华沙,并适当地改变你的电脑时区吗?在这种情况下应该怎么办?
如果您对这两个问题的回答
这就是数据库的全部内容。另一件事是应用程序内部使用的时间格式,这应该取决于您将使用该时间实际做什么。
您提到它通过 API 公开时间。应用程序会在每个请求上查询数据库吗?如果您在内部将时间存储为 UTC,您将需要这样做或以其他方式确保在 DST/时区更改时缓存时间将被调整/修剪。
它会对时间本身做些什么吗?就像打印事件将在 8 小时内发生 或在大约那个时间暂停自身?如果是,那么UTC可能会更好。当然,您需要考虑所有上述问题。
【讨论】:
因此,如果我将 DateTime 保存为 UTC DateTime(而不是 varchar,ToUniversalTime c#)在数据库中,那么当我填充时,我是否总是需要在客户端转换它以获得确切的日期?跨度> 【参考方案2】:我喜欢这样想:
计算机并不关心时间作为人类可以理解的表示。他们不关心时区、日期和时间字符串格式或任何这些。只有人类关心如何解释和表示时间。
让数据库做它擅长的事情:将时间存储为数字——可以是 UNIX 纪元(自 1970 年 1 月 1 日以来经过的秒数)或 UTC 时间戳(没有时区或夏令时信息)。仅在必要时才关心以人类可以理解的方式表示时间。这意味着在您的应用程序逻辑、报告系统、控制台应用程序或人类将查看数据的任何其他地方。
【讨论】:
问题是您不能从纪元或 UTC 日期/时间值返回到用户的原始本地时区日期/时间(不存储其他信息)。从本地时区转换为纪元或 UTC 是一种有损转换。 很难用 600 个字符回答,所以我不得不指出你要进一步阅读。这个 SO 问题是一个好的开始,并且包含许多进一步阅读的链接:***.com/questions/2532729/… 最重要的是理解问题域以及它是否包含物理时间、民用时间或两者兼而有之。 Epoch 可以处理物理时间(虽然我更喜欢 UTC),但对于我在民用时间上工作的系统来说通常更常见。 通过浮点表示时可能会发生有损。例如,持有 x-since epoch 的 long 是存储时间戳的绝佳方式,但在没有 long 的 javascript 中除外,因为,好吧,JavaScript。当您通过时间 I 和超出时区感知和不感知表示(查看您的 Python sql 驱动程序)时,也可能发生时区截断【参考方案3】:以下内容不适用于真正的多租户全球 SaaS 产品,因此本意见针对的是简单的“业务线”应用开发人员。
存储为 UTC 很好,但如果你这样做,有一个要求会导致痛苦:“你能给我写一份报告,告诉我每天发生多少 X 吗?”
如果您将日期存储为 UTC,则此要求会带来麻烦;您需要在应用服务器和您的报告中编写时区调整代码;您对包含日期条件的数据执行的每个临时查询都需要考虑到这一点。
如果您的申请符合以下条件:
-
每个实例都基于一个时区。
时区转换通常在办公时间之外进行,或者您并不真正关心事情的“持续时间”,以至于缺少一个小时左右会很重要。
我建议您将日期时间存储为本地日期时间,同时使用将您与服务器时区配置问题隔离开的库(例如 .net 世界中的 Noda.Time)。
【讨论】:
我认为你的观点很有道理,但我发现你的语气让我有些分心。如果您以更中立/正式的方式编写它,我认为您的回答会更受欢迎:)。【参考方案4】:如果您的系统间消息使用 ISO 8601,并且您的数据库正在存储原始本地时间 + 偏移量(如 MSSQL 中的 datetimeoffset
或 Mongo 中的 ISODate
,因为 ISO 8601 捕获它)并且您只使用 @ .NET 中的 987654326@ 或 Java 中的 OffsetDateTime
或您的代码中的一些等效项,则根本不需要转换。你只是存储它。所有比较功能都可以正常工作。
如果您在持久性中转换为 UTC,那么您就失去了从用户角度来看的偏移量。显示用户十年前签署文件的时间现在是一个难题。从 UTC 解决这个问题将意味着查找当时在该地区有效的 DST 规则。噩梦。
我相信我们都习惯于转换为 UTC 以实现持久性的原因是因为我们从来没有使用过正确的数据结构/数据类型来允许我们做正确的事情。
【讨论】:
有什么资源可以分享吗? 使用非 UTC 时间戳有几个问题,太多无法在评论中列出,但我会在最后添加一些链接。如果您需要时间戳的时区,可以将其存储在附加注释中。然后,您可以获得 UTC 的所有好处,同时仍然能够将时间戳转换为捕获所有原始数据的时间戳。 - 2018.javazone.no/program/0507d823-bfa9-483c-8aef-3881c38c315e - ideas.kentico.com/forums/239189-kentico-product-ideas/… Jon Skeet 今天就这个话题发表了文章。 codeblog.jonskeet.uk/2019/03/27/… 从用户的角度来看,转换为 UTC 并不会失去任何东西。您可以将 UTC 转换为任何时区,但不能将所有时区转换为 UTC。这就是为什么 UTC 是标准以及为什么它被称为通用的原因。有些人更进一步,总是存储两种时间格式以防出现问题(指定错误的时区)。【参考方案5】:我只存储时间组件,没有任何区域。每当 API 必须为其提供服务时,添加正确的日期并将其作为本地时间转换为该日期的 UTC。
数据库 = 17:00(使用不带日期的时间戳,小时为字节,分钟为字节,字符串)
检索 = 我们想要事件的日期 + 数据库 17:00 => 将其从本地转换为 UTC
这样您将始终提供正确的 UTC 时间。
【讨论】:
DST 日期在切换期间发生的事件怎么办?我有一些数据发生在 3 月 13 日凌晨 1 点或 2 点之间。当我尝试将其转换为 UTC 时出现错误,我不知道时间戳是否导致了切换。【参考方案6】:您实际上并没有像大多数时间 API 所假设的那样存储特定的时间点。如果您的数据库支持它(PostgreSQL 支持),则使用间隔,或者将其存储为一个整数,表示自午夜或相应的计划开始(星期一、月初等)以来的秒数(分钟/小时)。无论哪种情况,您都不必担心如何在系统之间处理“时间”,而只需在您的视图中将秒数转换为一天中的时间时,您就会感到非常头疼。
【讨论】:
【参考方案7】:我们不能总是计算给定 UTC 和时区的本地时间吗?我们不能真正可靠地存储时间本身编码的时间和时区,因为时区的偏移量可能会改变,而 ISO 标准只允许我们对可能改变的偏移量进行编码。所以,我们不能,比如说,存储在本地时区编码的未来时间,因为我们实际上还不知道偏移量!因此,以 UTC 存储时间并将时区存储为单独的条目,并在需要时进行计算,这样不容易出错。本地时间通常是一个实现细节。似乎当我们存储它时,我们可能会混淆关注点。大部分时间显示相对于时区的时间是视图的业务。通常,通过存储事物的组件并允许计算来组合它们,我们可以获得最大的灵活性。
【讨论】:
以上是关于以 UTC 存储时间总是一个好主意,还是以本地时间存储更好?的主要内容,如果未能解决你的问题,请参考以下文章
在填充的数据表中将 datetime 列从 utc 转换为本地时间
iOS将NSDate的UTC日期转换为本地时间以获取本地通知
TSQL:如何将本地时间转换为 UTC? (SQL Server 2008)