Grafana和MySQL相差8小时
背景说明
今日在用 Grafana 进行数据大屏看板制作 (数据源为 MySQL),其中有个面板是统计 “每日的用户反馈表单数量曲线图”,如图

因为要确保数据的准确性,于是进行了验证,抽样调查了其中的一个表单类型 异常反馈 的数量
1 | select count(1) as total from user_form_request where ct >= CURRENT_DATE() and form_type = 13; |
从上面的查询结果表现来看,后者和图中统计的结果数据才对得上(均为 32),也就是说 Grafana 统计的聚合数据比实际偏移了8个小时!
问题排查
从广大的网络文章看,主要集中都是说 Grafana 时区或者 MySQL时区设置有问题,或者两者的时区对不上!

1 | SELECT @@GLOBAL.time_zone, @@SESSION.time_zone; |
查询结果显示 SYSTEM,也即跟随服务系统的时区设置。
1 | # 执行下面命令进行查询 |
可以看出,服务器其实也是使用了 东八区。
也就是基本可以排除如各种社区说的服务器时区设置问题!
脑洞时刻
考虑到方便进一步定位,我这边获取了 Grafana 对应图表查询的模板内容
1 | select |
同时获取了该模板最近一次查询的 SQL
1 | select |
从查询条件 ufr.ct BETWEEN FROM_UNIXTIME(1681142400) AND FROM_UNIXTIME(1681228799)可知:当前查询的是2023-04-11 00:00:00 至 2023-04-11 23:59:59 的数据;这个时间范围是符合预期的(因为是我手动设置的)!
下面我跟进上面的 SQL 获取到对应结果内容
| from_unixtime 时间 | unix_timestamp 时间 | 表单名 | 提交量 |
|---|---|---|---|
| 2023-04-10 08:00:00 | 1681084800 | 封禁申诉 | 1 |
| 2023-04-10 08:00:00 | 1681084800 | 模拟器申请 | 1 |
| 2023-04-10 08:00:00 | 1681084800 | 充值异常 | 2 |
| 2023-04-10 08:00:00 | 1681084800 | 注销账号 | 1 |
| 2023-04-10 08:00:00 | 1681084800 | 找回账号 | 1 |
| 2023-04-10 08:00:00 | 1681084800 | 异常反馈 | 10 |
| 2023-04-10 08:00:00 | 1681084800 | 游戏建议 | 2 |
| 2023-04-11 08:00:00 | 1681171200 | 违规举报 | 34 |
| 2023-04-11 08:00:00 | 1681171200 | 注销账号 | 3 |
| 2023-04-11 08:00:00 | 1681171200 | 充值异常 | 3 |
| 2023-04-11 08:00:00 | 1681171200 | 找回账号 | 26 |
| 2023-04-11 08:00:00 | 1681171200 | 封禁申诉 | 10 |
| 2023-04-11 08:00:00 | 1681171200 | 游戏下载 | 4 |
| 2023-04-11 08:00:00 | 1681171200 | 模拟器申请 | 20 |
| 2023-04-11 08:00:00 | 1681171200 | 游戏建议 | 8 |
| 2023-04-11 08:00:00 | 1681171200 | 流水查询 | 2 |
| 2023-04-11 08:00:00 | 1681171200 | 异常反馈 | 33 |
是不是瞬间来疑问了:为何时间格式化会出现 4月10日 数据
茅塞顿开
回归之前说的 Grafana 和 MySQL 时差偏移 8h 的问题,再结合上面的数据和 SQL,我们是不是有足够的资本来怀疑 UNIX_TIMESTAMP(xxx) 的机制导致了这个问题呢?
也就是说 UNIX_TIMESTAMP() 会把我们的时间(此处假设是 2023-04-11 07:00:00)转成对应的 UTC 时间,而我们当前的服务器使用的是 东八区,所以转成 UTC 时间的时候就会减去 8h,即变成 UTC 2023-04-10 23:00:00。
然后结合上面 SQL 来代入 UNIX_TIMESTAMP('2023-04-11 07:00:00') DIV 86400 * 86400,本身是要取当天的零点(即 2023-04-11 00:00:00),最后因为被转成 UTC 2023-04-10 23:00:00,最后获得的是 2023-04-10 00:00:00;
而如果此时使用 FROM_UNIXTIME(UNIX_TIMESTAMP('2023-04-11 07:00:00') DIV 86400 * 86400),因为 MySQL 会根据本身的时区进行优化可阅读性,会格式成 东八区 时间,所以在 2023-04-10 00:00:00 的基础上加上 8h,造就了前面数据表看到的 2023-04-10 08:00:00。
解决方案
既然 UNIX_TIMESTAMP() 会默认帮我们减 8h,那我们只要默认给时间加 8h 再进行处理不就行了吗,下面是改造后的 Grafana 查询模板:
1 | select |





