跳到主要内容

TIMESTAMPTZ

描述

TIMESTAMPTZ 是 Doris 中用于存储带时区信息的日期时间数据类型,对应于标准 SQL 中的 TIMESTAMP WITH TIME ZONE。

在不同数据库系统中,带时区的时间戳类型有多种命名方式:

  • PostgreSQL 和 Oracle 使用 TIMESTAMP WITH TIME ZONE
  • SQL Server 使用 DATETIMEOFFSET
  • 其他一些数据库使用 TIMESTAMP WITH LOCAL TIME ZONE

根据 SQL 标准,单独的 TIMESTAMP 类型不应携带时区信息(等同于 TIMESTAMP WITHOUT TIME ZONE)。考虑到用户习惯和使用便捷性,Doris 选择使用 TIMESTAMPTZ 这个更加简洁的命名来表示带时区的时间戳类型。 注意目前 Doris 没有一个单独的 TIMESTAMP 类型,实际上用户完全可以使用 DATETIME 来存储时间。

TIMESTAMPTZ 的取值范围与 DATETIME 相同,为 [0000-01-01 00:00:00.000000, 9999-12-31 23:59:59.999999]。 TIMESTAMPTZ 支持指定精度,格式为 TIMESTAMPTZ(p),其中 p 表示精度,取值范围为 [0, 6],默认值为 0。换句话说,TIMESTAMPTZ 等同于 TIMESTAMPTZ(0)。 默认输出格式为 'yyyy-MM-dd HH:mm:ss.SSSSSS+XX:XX',其中 +XX:XX 表示时区偏移量(注意,SSSSSS 的位数由精度 p 决定)。

TIMESTAMPTZ 类型可以作为主键、分区列、分桶列。

工作原理

TIMESTAMPTZ 的实现并非在每行数据中单独存储时区信息,而是采用以下机制:

  1. 存储时:将输入的时间值统一转换为 UTC(世界协调时间)存储。
  2. 查询时:根据会话的时区设置(通过 time_zone 变量指定),将 UTC 时间自动转换为相应时区的时间进行展示。

因此,TIMESTAMPTZ 可以理解为一个带有时区转换功能的 DATETIME 类型,Doris 在内部自动完成时区的转换处理。

时区处理规则

  • 当输入字符串包含时区信息(如 "2020-01-01 00:00:00+03:00")时,Doris 会使用该时区信息进行转换。
  • 当输入字符串不包含时区信息(如 "2020-01-01 00:00:00")时,Doris 会使用当前会话的时区设置进行转换。

存储与使用

在 Doris 中,一个 TIMESTAMPTZ 类型字段占用 8 字节存储空间。

TIMESTAMPTZ 与 DATETIME 类型之间支持相互转换,转换过程中会根据时区进行适当调整。TIMESTAMPTZ 支持隐式转换为 DATETIME,这使得不直接支持 TIMESTAMPTZ 的函数也能处理此类型的数据。

举例

-- 使用当前时区(假设为 +08:00)转换没有时区信息的时间字符串
select cast("2020-01-01 00:00:00" as timestamptz);
+--------------------------------------------+
| cast("2020-01-01 00:00:00" as timestamptz) |
+--------------------------------------------+
| 2020-01-01 00:00:00+08:00 |
+--------------------------------------------+
-- TIMESTAMPTZ 可以支持微秒
select cast("2020-01-01 00:00:00.123456" as timestamptz(5));
+------------------------------------------------------+
| cast("2020-01-01 00:00:00.123456" as timestamptz(5)) |
+------------------------------------------------------+
| 2020-01-01 00:00:00.12345+08:00 |
+------------------------------------------------------+
-- 使用带有时区信息的时间字符串
select cast("2020-01-01 00:00:00 +03:00" as timestamptz);
+---------------------------------------------------+
| cast("2020-01-01 00:00:00 +03:00" as timestamptz) |
+---------------------------------------------------+
| 2020-01-01 05:00:00 +08:00 |
+---------------------------------------------------+
-- TIMESTAMPTZ 转换为 DATETIME(会根据当前时区进行转换)
select cast(cast("2020-01-01 00:00:00 +03:00" as timestamptz) as datetime);
+---------------------------------------------------------------------+
| cast(cast("2020-01-01 00:00:00 +03:00" as timestamptz) as datetime) |
+---------------------------------------------------------------------+
| 2020-01-01 05:00:00 |
+---------------------------------------------------------------------+
-- 将 DATETIME 转换为 TIMESTAMPTZ
select cast(cast('2023-01-02 01:00:00' as datetime) as timestamptz);
+--------------------------------------------------------------+
| cast(cast('2023-01-02 01:00:00' as datetime) as timestamptz) |
+--------------------------------------------------------------+
| 2023-01-02 01:00:00 +08:00 |
+--------------------------------------------------------------+
-- 在函数中使用 TIMESTAMPTZ
select HOUR(cast("2020-01-01 00:00:00 +03:00" as timestamptz));
+---------------------------------------------------------+
| HOUR(cast("2020-01-01 00:00:00 +03:00" as timestamptz)) |
+---------------------------------------------------------+
| 5 |
+---------------------------------------------------------+