InfluxDB 3.0 中改进的时区支持
作者:Jeffrey Smith / 开发者
2024 年 11 月 12 日
导航至
我们在 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-naive
和 tz-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 纪元秒)。
这两个概念之间的区别通过 tz
与 at 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”子句中设置时间范围,并且您希望它们基于特定时区(通常是您的本地时间)时,此函数非常有用。
例如,您想要将查询限制为最后一天,日期从美国/纽约边界开始
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
提供了所需的行为,即看到记录点的固定时间点,但在不同的时区显示。