【问题标题】:Flooring a unix timestamp with timezone support使用时区支持来构建 unix 时间戳
【发布时间】:2013-01-17 06:13:17
【问题描述】:

我有一个表,其中每一行都有一个时间戳。时间戳是一个unix时间戳。我想使用这些数据进行一些报告,这需要我按特定时间段对这些数据进行分组(现在,我们只说天:所以 86400 秒)。这可以通过设置时间戳来实现,即:

mysql> set time_zone='+00:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select NOW(), FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP()/86400)*86400);
+---------------------+----------------------------------------------------+
| NOW()               | FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP()/86400)*86400) |
+---------------------+----------------------------------------------------+
| 2013-01-17 06:06:37 | 2013-01-17 00:00:00                                |
+---------------------+----------------------------------------------------+
1 row in set (0.01 sec)

这使我可以进行以下数据汇总:

select FROM_UNIXTIME(FLOOR(timestamp/86400)*86400) groupts, count(some_id) from table group by groupts order by groupts;

所有这一切都完美无缺,现在我想将数据与其他报告进行比较,其中我只有特定时区的数据,比如说它的 EST。

不幸的是(很明显),地板不再起作用了:

mysql> set time_zone='-05:00';
Query OK, 0 rows affected (0.00 sec)

mysql> select NOW(), FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP()/86400)*86400);
+---------------------+----------------------------------------------------+
| NOW()               | FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP()/86400)*86400) |
+---------------------+----------------------------------------------------+
| 2013-01-17 01:10:38 | 2013-01-16 19:00:00                                |
+---------------------+----------------------------------------------------+
1 row in set (0.00 sec)

这最终让我想到了我的问题: 有没有办法根据特定的时区来确定时间戳?即,地板将确保该时区 00:00-23:59 的所有值最终都属于特定组?

谢谢!

【问题讨论】:

    标签: database language-agnostic time timezone


    【解决方案1】:

    您需要将时区偏移从 UTC 转换为秒;然后,您需要在除法和乘法之前从 Unix 时间戳中添加或减去该偏移量,然后再将其加回。

    例如:

    我们可以在 UTC-05:00 时区(美国/东部或美国/纽约)中建立日期 2012-01-17 的 UTC 值范围:

    $ timestamp -Z -z -05:00 1358398800 1358485200
    1358398800 = Thu Jan 17 00:00:00 2013 -05:00
    1358485200 = Fri Jan 18 00:00:00 2013 -05:00
    $ timestamp -Z -z 00:00 1358398800 1358485200
    1358398800 = Thu Jan 17 05:00:00 2013 +00:00
    1358485200 = Fri Jan 18 05:00:00 2013 +00:00
    $
    

    时区偏移量与 UTC (5 * 3,600) 相差 -18,000 秒,当然一天有 86,400 秒。

    然后我们可以用bc 表明计算应该是:

    • ((utc_time + tz_offset) / secs_per_day) * secs_per_day - tz_offset

    例如,我们可以使用bc进行计算:

    $ bc
    scale=0
    a=1358398800
    b=a+86400
    c=-18000
    d=86400
    ((a+c)/d)*d-c
    1358398800
    ((b-1+c)/d)*d-c
    1358398800
    ((b+c)/d)*d-c
    1358485200
    b
    1358485200
    quit
    $
    

    如您所见,美国/东部时区 2012-01-17 期间的时间都被归为同一组(使用极端时间值演示)。

    因此,只要您可以以秒为单位计算时区与 UTC 的偏移量,格林威治子午线以西的时区为负值,其以东的时区为正值,那么您就可以使用显示的计算.

    SELECT NOW(), FROM_UNIXTIME(FLOOR((UNIX_TIMESTAMP() + (-18000))/86400)*86400 - (-18000));
    

    概括:

    FLOOR((timestamp + (offset_in_seconds))/86400)*86400 - (offset_in_seconds)
    

    其中 offset_in_seconds 可以是正数或负数。

    【讨论】:

    • 我已编辑您的答案并修复了查询。实际查询应该是:FLOOR((timestamp + (offset_in_seconds))/86400)*86400 - (offset_in_seconds)。感谢您的精彩回答!
    猜你喜欢
    • 1970-01-01
    • 2012-05-06
    • 2015-07-26
    • 2013-05-20
    • 1970-01-01
    • 2019-07-14
    • 2017-04-25
    • 2015-10-07
    • 2014-01-09
    相关资源
    最近更新 更多