mysql - 什么足以将来自多个时区的日期/时间存储在数据库中以进行准确计算?

标签 mysql sql sql-server oracle timezone

这是一个困难的问题。事实上,SQL 标准和大多数主要数据库似乎都很难实现。

将所有日期时间转换为 UTC 允许在记录之间轻松进行比较,但会丢弃时区信息,这意味着您不能对它们进行计算(例如,将 8 个月添加到存储的日期时间),也不能在它们所在的时区检索它们存储在。所以天真的方法已经过时了。

除了时间戳(例如 postgres 中带有时区的时间戳)之外,还存储与 UTC 的时区偏移量似乎就足够了,但不同的时区可以在一年中的某个时间点具有相同的偏移量,而在 6 个月后具有不同的偏移量由于夏令时。例如,您现在(8 月)可以让纽约和智利都使用 UTC-4,但在 11 月 4 日之后,纽约将是 UTC-5,而智利(9 月 2 日之后)将是 UTC-3。因此,仅存储偏移量也不允许您进行准确的计算。与上述天真的方法一样,它也会丢弃信息。

如果您将时区标​​识符(例如 America/Santiago)与时间戳一起存储会怎样?这将使您能够区分智利日期时间和纽约日期时间。但这还不够。如果您正在存储到期日期,比如 future 6 个月的午夜,并且 DST 规则发生变化(不幸的是政治家喜欢这样做)那么您的时间戳将是错误的并且到期可能发生在晚上 11 点或凌晨 1 点。这对您的应用程序来说可能不是什么大事。所以使用时间戳也会丢弃信息。

似乎要真正准确,您需要将本地日期时间(例如,使用非时区感知时间戳类型)与时区标识符一起存储。为了支持更快的比较,您可以缓存它的 utc 版本,直到您使用的时区数据库更新,然后更新缓存的值(如果它已更改)。因此,这将是 2 个简单的时间戳类型加上一个时区标识符和某种外部 cron 作业,该作业检查时区数据库是否已更改并为缓存的时间戳运行适当的更新查询。

这是一个准确的解决方案吗?还是我还缺少什么?可以做得更好吗?

我对 MySQL、SQL Server、Oracle、PostgreSQL 和其他处理 TIMESTAMP WITH TIME ZONE 的 DBMS 的解决方案很感兴趣。

最佳答案

您很好地总结了问题。遗憾的是,答案是按照您所描述的去做。

要使用的正确格式确实取决于时间戳应该表示的语用学。它通常可以分为过去事件和 future 事件(尽管也有异常(exception)):

  • 过去的事件可以而且通常应该存储为永远不会以不同方式重新解释的东西。 (例如:带有数字时区的 UTC 时间戳)。如果应保留指定的时区(以向用户提供信息),则应将其分开。

  • future 的事件需要您所描述的解决方案。本地时间戳和命名时区。这是因为您希望在时区规则更改时更改该事件的“实际”(UTC) 时间。

我会质疑时区转换是否是一种开销?通常很快。如果您看到真正显着的性能下降,我只会经历缓存的痛苦。有(正如您所指出的)一些需要缓存的大型操作(例如根据实际 (UTC) 时间对数十亿行进行排序。

如果您出于性能原因需要将 future 的事件缓存在 UTC 中,那么是的,您需要实现一个流程来更新缓存的值。根据 DB 的类型,这可能由系统管理员完成,因为 TZ 规则很少更改。

关于mysql - 什么足以将来自多个时区的日期/时间存储在数据库中以进行准确计算?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12123118/

相关文章:

sql-server - 在 postgresql 和 SQL Server 数据库之间移动数据的最佳方式是什么

php - PHP MySQL 如何检查某个查询是否在数据范围内?

php - 我如何使用 MySQL Join 按最后回复对论坛主题进行排序?

php - 使用 $row->element 而不是 $row ["element"的数据库查询(while 或 foreach)]

mysql - IN 内的 SQL 查询结果

sql - 建议 : dilemma in designing typical user-group-relation DB tables

mysql - 如何返回 mysql 中的所有匹配项,其中值出现在位置 n 的字符串中?

mysql - 连接不同列中的 2 个查询

sql - 从另一个表中选择列中的相似值并在主表中使用另一个表值

sql - 远程 MSSQL/ODBC 与 Rails 同步