使用时区支持对unix时间戳进行地板分层

时间:2013-01-17 06:13:18

标签: database language-agnostic time timezone

我有一个表,每行都有一个时间戳。时间戳是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的所有值最终都在特定组中?

谢谢!

1 个答案:

答案 0 :(得分:0)

您需要将时区偏移量从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可以是正数或负数。