如何按日期分组,考虑时区和 DST?

Posted

技术标签:

【中文标题】如何按日期分组,考虑时区和 DST?【英文标题】:How to group by date, accounting for timezones and DST? 【发布时间】:2015-03-16 21:27:35 【问题描述】:

我的数据库中存储了一堆事件。每个事件都有一个开始时间,以 UTC 格式存储为 DATETIME。每个用户都可以选择自己的时区。

我想显示一个日历,它只显示该月每一天的事件数。我不能GROUP BY DATE(start_dt) 因为用户的一天不是[必然]从 00:00:00 UTC 开始的。此外,用户的时区可能会在月中进行 DST 切换。

那么我唯一的选择是获取给定月份的每个事件,然后用我的服务器端语言对它们进行分组和计数吗?

【问题讨论】:

【参考方案1】:

你可以试试

SELECT ... FROM ... GROUP BY DATE(CONVERT_TZ(start_dt,'UTC','America/Vancouver'))

请注意,您需要先load the timezone data into mysql 才能使用。

【讨论】:

或者使用数字偏移量作为CONVERT_TZ() (manual) 的第三个参数,这样就不需要时区表,例如。 CONVERT_TZ('2004-01-01 12:00:00','UTC','+10:00'); @RandomSeed 问题在于夏令时。月初的偏移量可能与月底的偏移量不同。 @RandomSeed 你在你的例子中犯了一个小错误。应该是:CONVERT_TZ('2004-01-01 12:00:00','+00:00','+10:00');,因为使用UTC 而不是+00:00 仍然会导致NULL 结果。【参考方案2】:

很遗憾,DATETIME 列存储时没有时区信息:

当前时区设置不会影响 UTC_TIMESTAMP() 等函数显示的值或 DATE、TIME 或 DATETIME 列中的值。这些数据类型中的值也不以 UTC 格式存储;仅当从 TIMESTAMP 值转换时,时区才适用于它们。如果您想要 DATE、TIME 或 DATETIME 值的特定于区域设置的算术,请将它们转换为 UTC,执行算术,然后再转换回来。 [MySQL Docs]

幸运的是,这确实意味着日期/时间函数应该与时区支持一起使用,但仅限于 TIMESTAMP 列。一旦进入TIMESTAMP 列,日期/时间函数应该能够考虑@@session.time_zone,您可以根据需要更改它以获得不同的时区。

因此,您的选择是让您的表包含 DATETIME 列,并自己进行所有分组,或者将这些列转换为 TIMESTAMP 并让 MySQL 来做 - 但如果这些列已经处于不同且不一致的时区,你会为你完成你的工作......

【讨论】:

您只需要记住 tzdata 不是一成不变的,一旦您将某些日期转换为时间戳,一旦更改时区规则,您就不需要正确恢复它们。【参考方案3】:

您可以在中间切换到用户 tz:

  SET @@session.time_zone = "+05:00"; 
  select ... from .. group by MONTH(datefield);
  SET @@session.time_zone = @@global.time_zone;

刚刚找到:How do I set the time zone of MySQL?

【讨论】:

更改时区实际上不会影响我的DATETIME 字段吗? 不幸的是它不会。来自 MySQL 文档:“当前时区设置不会影响函数显示的值,例如 UTC_TIMESTAMP() 或 DATE、TIME 或 DATETIME 列中的值。这些数据类型中的值也不以 UTC 存储;时区适用于它们仅在从 TIMESTAMP 值转换时。如果您想要 DATE、TIME 或 DATETIME 值的特定于区域设置的算术,请将它们转换为 UTC,执行算术,然后再转换回来。" 不!试试SET @@session.time_zone = "+03:00"; select now() from dual;它不会改变你的时钟... @AxelAmthor 那是个问题。按DATE() 分组将与我没有设置时区完全相同。 据我所知,让 MySQL 执行区域设置感知操作的唯一方法是使用 TIMESTAMP 列执行所有操作;那么会话时区将用于分组等。

以上是关于如何按日期分组,考虑时区和 DST?的主要内容,如果未能解决你的问题,请参考以下文章

如何将熊猫中的日期时间列全部转换为同一时区

BigQuery转换为不同的时区

通过考虑展望日来分组日期

SQLAlchemy:如何按两个字段分组并按日期过滤

如何使用 Linq 按日期时间和平均结果对字典进行分组

PHP JSON 按相同值分组