You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Grafana与PostgreSQL:基于浏览器时区实现班次数据聚合的问题

解决Grafana中基于浏览器时区的班次聚合问题

你的核心问题在于直接从UTC时间戳提取了小时,而没有转换到浏览器时区。Grafana提供了内置的$__timezone变量,可以获取当前浏览器的时区(比如Asia/ShanghaiAmerica/New_York),我们可以利用这个变量将UTC时间转换为目标时区后再提取小时,从而正确分配班次编号。

针对不同数据库的修改方案

方案1:PostgreSQL

WITH base AS (
 SELECT 
  "Timestamp" AS time,
  -- 步骤:1. 把毫秒级时间戳转成UTC时间;2. 转换为浏览器时区;3. 提取小时
  extract('hour' FROM to_timestamp("Timestamp"/1000) AT TIME ZONE 'UTC' AT TIME ZONE '$__timezone') AS h,
  [some_metric]
 FROM [table]
 WHERE $__unixEpochFilter("Timestamp"/1000)
), shifts AS (
 SELECT *,
 CASE
 WHEN (h >= 5 AND h < 13 ) THEN 1 -- 早班
 WHEN (h >=13 AND h <21) THEN 2 -- 中班
 ELSE 3 -- 晚班
 END AS shift_nr
 FROM base
)
SELECT shift_nr, avg([some_metric]) AS avg_metric
FROM shifts
GROUP BY shift_nr
ORDER BY shift_nr;

方案2:MySQL

MySQL的时区转换函数是CONVERT_TZ,语法略有不同:

WITH base AS (
 SELECT 
  "Timestamp" AS time,
  -- 步骤:1. 转成UTC datetime;2. 转换为浏览器时区;3. 提取小时
  HOUR(CONVERT_TZ(FROM_UNIXTIME("Timestamp"/1000), 'UTC', '$__timezone')) AS h,
  [some_metric]
 FROM [table]
 WHERE $__unixEpochFilter("Timestamp"/1000)
), shifts AS (
 SELECT *,
 CASE
 WHEN (h >= 5 AND h < 13 ) THEN 1
 WHEN (h >=13 AND h <21) THEN 2
 ELSE 3
 END AS shift_nr
 FROM base
)
SELECT shift_nr, avg([some_metric]) AS avg_metric
FROM shifts
GROUP BY shift_nr
ORDER BY shift_nr;

关键说明

  1. 时区设置验证:确保Grafana的全局时区设置为Browser time zone(路径:Admin -> Settings -> Time zone),这样$__timezone变量才会正确返回当前浏览器的时区信息。
  2. 时间戳单位:你的时间戳是毫秒级的,所以用/1000转成秒级适配to_timestampFROM_UNIXTIME,如果是秒级时间戳可以去掉这个除法。
  3. 班次边界处理CASE语句里的<>=确保了班次时间的闭合性(比如13:00整属于中班,21:00整属于晚班),如果需要调整边界可以修改条件。

替代思路(无需SQL修改)

如果你的数据库不支持时区转换,或者想更灵活地处理,可以使用Grafana的Transform功能:

  • 先查询出原始的UTC时间戳和指标数据。
  • 添加Convert Field Type转换,将时间戳转成日期时间类型(选择浏览器时区)。
  • 添加Extract fields转换,从日期时间中提取小时。
  • 最后添加Group by转换,按班次编号分组聚合指标。
    不过这种方式在数据量较大时,性能不如SQL端直接处理。

内容的提问来源于stack exchange,提问作者eyei

火山引擎 最新活动