InfluxDB 3.0 中改进的时间区域支持

导航至

我们已在 InfluxDB 3.0 SQL 中添加了一个新功能 tz,以改进与时间区域工作的人体工程学。本文将详细介绍如何使用此功能,以及在什么情况下使用此功能比现有的 SQL 时间区域函数更合适。

tz 函数

tz 函数的目标是一致地简化相对于 Unix 纪元的各种时间区域之间的转换。这与提供不同语义的 at time zone 语法形成对比。

用法

tz 函数接受一个或两个参数。第一个参数始终是纳秒级时间戳,可以是任何时间区域或没有时间区域。第二个参数是有效的时间区域字符串。如果没有提供,默认为 UTC。

以下是如何使用 tz 的示例

-- Convert from un-timezoned to 'Europe/Brussels'
SELECT tz('2024-04-01T00:00:20', 'Europe/Brussels') as t;
+---------------------------+
| t                         |
+---------------------------+
| 2024-04-01T02:00:20+02:00 |
+---------------------------+

-- Convert from un-timezoned to UTC
SELECT tz('2024-04-01T00:00:20') as t, arrow_typeof(tz('2024-04-01T00:00:20')) as type;
+----------------------+------------------------------------+
| t                    | type                               |
+----------------------+------------------------------------+
| 2024-04-01T00:00:20Z | Timestamp(Nanosecond, Some("UTC")) |
+----------------------+------------------------------------+

-- Convert from un-timezoned to America/New_York and then to America/Denver
SELECT tz(tz('2024-04-01T00:00:20', 'America/New_York'), 'America/Denver') as t;
+---------------------------+
| t                         |
+---------------------------+
| 2024-03-31T18:00:20-06:00 |
+---------------------------+

需要注意的是,tz 的返回类型将始终与时间区域相关联,即使该时间区域是 UTC。这对于像 Python(以及其他语言)这样的语言很重要,在这些语言中,不支持比较 tz-naivetz-aware 类型。任何利用此功能的客户端代码都需要准备好处理具有时间区域感知的数据。

SELECT arrow_typeof(tz('2024-04-01T00:00:20'));
+-----------------------------------------------+
| arrow_typeof(tz(Utf8("2024-04-01T00:00:20"))) |
+-----------------------------------------------+
| Timestamp(Nanosecond, Some("UTC"))            |
+-----------------------------------------------+

什么是时间

为了解释这个变化,将给定时间视为“绝对”或“实际时间”是有用的。

绝对时间是相对于 UTC 纪元的。例如,时间 2024-08-01T06:00:00Z 是 1722492000 纪元秒,相当于 2024-08-01T00:00:00-06:00(美国/丹佛时区)。

实际时间是您会在特定时区时钟上看到的时间。例如,您可能想要 2024-07-17T17:00:00 时在美洲/丹佛的时间,因此您的时间将表示为 2024-07-17T17:00:00-06:00(1721257200 纪元秒)。

这两个概念之间的区别可以用 tzat time zone 来说明。

让我们看一个简单的例子

SELECT '2024-04-01T00:00:20Z'::timestamp AT TIME ZONE 'Europe/Brussels';
+------------------------------+
| Utf8("2024-04-01T00:00:20Z") |
+------------------------------+
| 2024-04-01T00:00:20+02:00    |
+------------------------------+

SELECT tz('2024-04-01T00:00:20', 'Europe/Brussels');
+---------------------------------------------------------+
| tz(Utf8("2024-04-01T00:00:20"),Utf8("Europe/Brussels")) |
+---------------------------------------------------------+
| 2024-04-01T02:00:20+02:00                               |
+---------------------------------------------------------+

当时间戳没有时区信息(在InfluxDB 3.0中的默认行为)时,at time zone转换将返回指定时区的墙上时间。此函数在设置“where”子句中的时间边界时非常有用,您希望它们基于特定的时区(通常是本地时间)。

例如,您想将查询限制在上一个以America/New_York时区为起点的最后一天。

select * from my_cool_stuff where time > '2024-01-01' at time zone 'America/New_York' and time < '2024-01-02' at time zone 'America/New_York'

函数tz总是返回指定时区的绝对时间。当您有已经写入InfluxDB(根据行协议规范总是UTC 时间戳)的数据,并且希望以本地时区显示它们时,这非常有用。

例如,您有Telegraf将内存使用情况写入数据库。您不需要对每个值都进行心理偏移,可以使用tz函数。

select
    time,
    time at time zone 'America/New_York' as time_atz,
    tz(time, 'America/New_York') as time_tz 
from mem order by time limit 3;
+----------------------+---------------------------+---------------------------+
| time                 | time_atz                  | time_tz                   |
+----------------------+---------------------------+---------------------------+
| 2020-06-11T16:51:50Z | 2020-06-11T16:51:50-04:00 | 2020-06-11T12:51:50-04:00 |
| 2020-06-11T16:52:00Z | 2020-06-11T16:52:00-04:00 | 2020-06-11T12:52:00-04:00 |
| 2020-06-11T16:52:10Z | 2020-06-11T16:52:10-04:00 | 2020-06-11T12:52:10-04:00 |
+----------------------+---------------------------+---------------------------+

在上面的例子中,time_atz不是数据写入时间的准确表示。它实际上将点向未来移动了4小时。time_tz提供了期望的行为,即在记录点看到固定的时间点,但在不同的时区显示。