Go中InfluxDB 2.x按周/月聚合需用Flux脚本:周聚合用date.truncate(t:r._time,unit:1w,offset:1d)对齐自然周(周日始),月聚合用date.truncate(...unit:1mo)避免30天陷阱,并显式指定timeZone。

Go 中用 InfluxDB 2.x 的 Flux 查询按周/月聚合,关键在 aggregateWindow 和 timeZone
InfluxDB 2.x 不再支持类似 SQL 的 GROUP BY time(1w) 语法,必须用 Flux 脚本。Go 客户端(如 influxdb-client-go)只是发请求,聚合逻辑全写在 Flux 字符串里。直接拼错时间单位或时区会导致结果偏移一整天甚至跨周。
-
start和stop必须是 RFC3339 格式(如"2024-01-01T00:00:00Z"),不能用本地时间字符串 - 按周聚合用
every: 1w,但默认从周一 00:00 UTC 开始切窗;若要按自然周(周日~周六),得加offset: -1d - 按月聚合不能写
every: 1mo—— Flux 不识别mo,必须用every: 30d或更稳妥的date.truncate手动对齐 - 时区不显式指定时,
aggregateWindow默认用 UTC,中国用户常漏加timeZone: "Asia/Shanghai",导致周统计错位
Flux 脚本里正确对齐“自然周”的写法
比如统计每自然周(周日 00:00 到下个周六 23:59)的平均值,不能只靠 every: 1w。Flux 的周切窗固定以周一为起点,所以得用 date.truncate 先把时间归到最近的周日,再分组:
from(bucket: "mydb")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "cpu" and r._field == "usage_percent")
|> map(fn: (r) => ({ r with _time: date.truncate(t: r._time, unit: 1w, offset: 1d) }))
|> group(columns: ["_time"])
|> mean(column: "_value")
这里 offset: 1d 是关键:把周一零点往前推一天,变成周日零点。注意不是 -1d —— Flux 的 offset 是相对于单位起点的偏移,正数向后、负数向前,但 1w 的起点是周一,+1d 就落到周日。
Go 客户端调用 Flux 查询的最小可行代码
别用 QueryAPI.Query 的老式行协议方式,它不支持 Flux 返回的表结构。必须用 QueryAPI.QueryWithOptions 并设 dialect: flux.Dialect{Header: true},否则字段名和数据对不上。
立即学习“go语言免费学习笔记(深入)”;
- Flux 脚本必须完整,包含
from、range、filter,不能只写聚合部分 - Go 中传时间范围用
time.Time.UTC().Format(time.RFC3339),别用Local() - 解析结果时,
table.Record().ValueByKey("_value")才是聚合值,_time是窗口起始时间(不是原始时间戳) - 如果返回空表,大概率是
range时间没覆盖数据,或filter条件过严(比如字段名大小写错)
按月聚合时避免“30天陷阱”
写 every: 30d 看似简单,但 1 月 31 日 + 30 天 = 3 月 2 日,跳过了 2 月,导致 2 月数据全被归到 1 月窗口。真正按日历月聚合,得用 date.truncate 对齐到每月 1 日:
|> map(fn: (r) => ({ r with _time: date.truncate(t: r._time, unit: 1mo) }))
|> group(columns: ["_time"])
|> sum(column: "_value")
1mo 在 Flux 中是合法单位,且会自动处理大小月和闰年。但注意:date.truncate(t: t, unit: 1mo) 总是截到当月第一天 00:00,所以窗口是 [1日00:00, 下月1日00:00),符合常规“月度统计”预期。这个细节文档里藏得深,很多人卡在 every: 30d 的偏差上。


















