转换为 TIMESTAMP_NS 类型
描述
TIMESTAMP_NS 具有固定纳秒精度,精确取值范围为 [1677-09-21 00:12:43.145224192, 2262-04-11 23:47:16.854775807],不接受精度参数。
字符串和数字通常采用与转换为 DATETIME 相同的字段映射。在严格和非严格 CAST 模式下,TIMESTAMP_NS 支持的字符串格式都与对应模式下的 DATETIME 完全一致。字符串格式能力的唯一区别是 TIMESTAMP_NS 的小数秒精度最高为 9 位,而 DATETIME 最高为 6 位。
语法
CAST(<source_expr> AS TIMESTAMP_NS)
TRY_CAST(<source_expr> AS TIMESTAMP_NS)
支持的源类型
| 源类型 | 转换行为 |
|---|---|
CHAR、VARCHAR、STRING | 按对应的 DATETIME 严格或非严格模式语法解析日期时间,小数秒精度最高为 9 位。 |
| 整数类型 | 将数值解释为紧凑日期或日期时间。 |
FLOAT | 使用单精度浮点输入实际表示的值;有效数字丢失可能使较大的紧凑日期时间变为非法值。 |
DOUBLE | 使用双精度浮点输入实际表示的值;小数部分表示小数秒。 |
DECIMAL 类型 | 将整数部分解释为紧凑日期或日期时间,将小数部分解释为小数秒。 |
DATE | 补充 00:00:00.000000000。 |
DATETIME(p) | 保留日期时间字段,并在小数部分末尾补零到 9 位。 |
TIME(p) | 将输入时长加到当前日期的午夜。 |
TIMESTAMPTZ(p) | 将绝对时间转换到当前会话时区,然后移除时区。 |
TIMESTAMP_NS | 原值返回。 |
VARIANT | 提取兼容的标量值,并应用对应的字符串、数字或时间类型转换规则。 |
NULL | 返回 NULL。 |
从 BOOLEAN、JSON、IP、二进制和复杂类型等不支持的类型转换时,会在分析阶段失败。这属于类型错误而不是值转换错误,因此非严格模式的 CAST 和 TRY_CAST 都不会将其转换为 NULL。
从字符串转换
严格模式
当 enable_strict_cast = true 时,支持的格式和解析规则与 DATETIME 严格模式的字符串转换完全一致,包括日期和时间字段、两位年份、省略时间字段、连续数字、空白字符以及时区后缀等规则。
非严格模式
当 enable_strict_cast = false 时,支持的格式和解析规则与 DATETIME 非严格模式的字符串转换完全一致。所有严格模式格式仍然合法,同时也支持 DATETIME 非严格模式允许的额外分隔符、日期时间分隔方式以及首尾空白字符。
两种模式在转换为 TIMESTAMP_NS 时的差异也与 DATETIME 相同:格式错误或值域错误在严格模式下报错,在非严格模式下返回 NULL。
小数秒
与对应的 DATETIME 字符串格式相比,唯一区别是支持的小数秒精度:
- 目标精度固定为 9 位。小数不足 9 位时,在右侧补零。
- 小数超过 9 位时,按四舍五入规则处理。第 10 位决定第 9 位是否加一,后续数字不影响结果。
- 小数舍入产生的进位会正常传递到秒、日期或年份。
- 小数舍入和时区转换完成后,Doris 才检查
TIMESTAMP_NS的取值范围。
时区处理
TIMESTAMP_NS 不存储时区:
- 不带时区后缀时,解析得到的日期时间字段保持不变。
- 带数字偏移、UTC 标识符或 IANA 时区名称时,Doris 将输入的绝对时间转换到当前会话时区,再存储不带时区的日期时间。
- 值存储后,再修改会话时区不会改变已存储的值。
可接受的时区后缀和时区名称请参见 DATETIME 字符串转换规则和时区。
以下示例假设 time_zone = '+08:00':
| 字符串 | 模式 | 结果 | 说明 |
|---|---|---|---|
2024-02-29 12:34:56.123456 | 两种模式 | 2024-02-29 12:34:56.123456000 | 补零到 9 位小数。 |
2024-02-29 12:34:56.1234567894 | 两种模式 | 2024-02-29 12:34:56.123456789 | 第 10 位小于 5,向下舍入。 |
2024-02-29 12:34:56.1234567895 | 两种模式 | 2024-02-29 12:34:56.123456790 | 第 10 位等于 5,向上舍入。 |
2024-02-29 12:34:56.9999999995 | 两种模式 | 2024-02-29 12:34:57.000000000 | 舍入进位到下一秒。 |
2024-02-29T04:34:56.123456789Z | 两种模式 | 2024-02-29 12:34:56.123456789 | 从 UTC 转换到会话时区,然后移除时区。 |
2023-7-4T9-5-3.1Z | 仅非严格模式 | 2023-07-04 17:05:03.100000000 | 使用非严格模式的分隔符和首尾空白字符。 |
2024-02-30 12:34:56 | 两种模式 | 非法 | 公历中不存在 2 月 30 日。 |
2024-01-01 00:00:00.123.456 | 两种模式 | 非法 | 小数秒语法错误。 |
边界舍入
最终范围检查在舍入之后进行。因此,紧邻边界之外的输入可能在舍入后变为合法值,而位于上边界的输入也可能因向上舍入而变为非法值。
| 字符串 | 结果 |
|---|---|
1677-09-21 00:12:43.1452241914 | 非法:舍入后仍小于下限 |
1677-09-21 00:12:43.1452241915 | 1677-09-21 00:12:43.145224192 |
2262-04-11 23:47:16.8547758074 | 2262-04-11 23:47:16.854775807 |
2262-04-11 23:47:16.8547758075 | 非法:舍入后大于上限 |
从数字转换
所有整数、浮点数和小数类型都可以转换为 TIMESTAMP_NS,不支持 BOOLEAN。
整数部分的字段映射、两位年份规则和合法的紧凑表示形式与数字转换为 DATETIME相同。具体来说,合法表示包含 3、4、5、6、8 或 14 位整数,小数部分表示小数秒。
紧凑日期时间与小数部分必须组成位于 TIMESTAMP_NS 取值范围内的值。小数秒按照与字符串输入相同的四舍五入规则补齐或舍入到固定 9 位。
从整数类型转换
整数类型没有小数部分。Doris 按照紧凑数字的字段映射进行转换,并在结果末尾补充 .000000000。
| 整数值 | 结果 | 说明 |
|---|---|---|
123 | 2000-01-23 00:00:00.000000000 | 3 位紧凑日期。 |
20240229 | 2024-02-29 00:00:00.000000000 | 8 位紧凑日期。 |
20240229123456 | 2024-02-29 12:34:56.000000000 | 14 位紧凑日期时间。 |
16770921001243 | 非法 | 结果小于下限。 |
22620412000000 | 非法 | 结果大于上限。 |
从 FLOAT 转换
转换使用 FLOAT 输入在 CAST 前实际表示的十进制值。单精度浮点数的有效数字通常不足以表示 14 位紧凑日期时间,因此较大的输入可能丢失数字并变成非法日期时间。对于较大的紧凑数值,应使用 DOUBLE 或 DECIMAL。
| FLOAT 输入表达式 | 严格模式结果 | 非严格模式结果 | 说明 |
|---|---|---|---|
CAST(123 AS FLOAT) | 2000-01-23 00:00:00.000000000 | 2000-01-23 00:00:00.000000000 | 实际表示的值是精确的。 |
CAST(20240229123456.125 AS FLOAT) | 报错 | NULL | 有效数字丢失使实际表示的紧凑日期时间变为非法值。 |
从 DOUBLE 转换
转换使用 DOUBLE 输入在 CAST 前实际表示的十进制值。双精度浮点数可以精确表示所有紧凑 TIMESTAMP_NS 值的 14 位整数部分,但不能用二进制精确表示的小数仍可能在转换前发生舍入。如果需要保留输入的每一位小数,应使用 DECIMAL。
| DOUBLE 输入表达式 | 结果 | 说明 |
|---|---|---|
CAST(20240229123456.125 AS DOUBLE) | 2024-02-29 12:34:56.125000000 | 整数和小数部分均可精确表示。 |
从 DECIMAL 转换
DECIMAL 保留字面量的十进制表示。超过纳秒精度的部分按照四舍五入规则舍入到 9 位小数。
| DECIMAL 输入表达式 | 结果 | 说明 |
|---|---|---|
CAST(20240229123456.1234567895 AS DECIMAL(24, 10)) | 2024-02-29 12:34:56.123456790 | 将小数部分舍入到纳秒。 |
错误处理
严格和非严格模式采用相同的数字映射。如果实际表示的数值无法得到合法且位于范围内的 TIMESTAMP_NS,严格模式报错,非严格模式返回 NULL。两种模式下输入为 NULL 时均返回 NULL。
从日期时间类型转换
从 DATE 转换
Doris 在输入日期后补充 00:00:00.000000000,再检查 TIMESTAMP_NS 的取值范围。由于下边界日期的午夜超出范围,因此 1677-09-21 无法转换;最早可转换的 DATE 是 1677-09-22,最晚是 2262-04-11。
输入 DATE | 结果 |
|---|---|
1677-09-21 | 非法 |
1677-09-22 | 1677-09-22 00:00:00.000000000 |
2262-04-11 | 2262-04-11 00:00:00.000000000 |
2262-04-12 | 非法 |
从 DATETIME 转换
DATETIME 和 TIMESTAMP_NS 都不带时区,因此 Doris 保留日期时间字段,不进行时区调整。DATETIME(p) 的小数在右侧补零到 9 位,不会补充源值中不存在的精度信息。
补零后的结果必须在 TIMESTAMP_NS 范围内。由于 DATETIME 最多支持微秒精度,下边界日期最早可转换的值是 1677-09-21 00:12:43.145225,上边界日期最晚可转换的值是 2262-04-11 23:47:16.854775。
输入 DATETIME(6) | 结果 |
|---|---|
1677-09-21 00:12:43.145224 | 非法 |
1677-09-21 00:12:43.145225 | 1677-09-21 00:12:43.145225000 |
2024-02-29 12:34:56.123456 | 2024-02-29 12:34:56.123456000 |
2262-04-11 23:47:16.854775 | 2262-04-11 23:47:16.854775000 |
2262-04-11 23:47:16.854776 | 非法 |
从 TIME 转换
Doris 从当前会话时区中当前日期的午夜开始,加上带符号的 TIME 时长。该时长可以跨越日期边界。小数部分最多具有微秒精度,转换时在右侧补零到 9 位。最后,Doris 检查得到的日期时间是否在 TIMESTAMP_NS 范围内。
例如,假设当前日期为 2025-04-29:
输入 TIME(6) | 结果 |
|---|---|
12:34:56.123456 | 2025-04-29 12:34:56.123456000 |
500:00:00.000000 | 2025-05-19 20:00:00.000000000 |
-128:00:00.000000 | 2025-04-23 16:00:00.000000000 |
由于转换结果依赖当前日期,需要可复现的日历日期时,应改用显式的 DATE 或 DATETIME。
从 TIMESTAMPTZ 转换
Doris 将输入表示的绝对时间转换到当前会话时区,移除时区,并在源值的小数右侧补零到 9 位。最终得到的本地日期时间必须在 TIMESTAMP_NS 范围内。
因此,修改 time_zone 可能改变转换结果,也可能使边界值移入或移出支持范围。
SET time_zone = '+08:00';
SELECT CAST(CAST('2024-02-29 04:34:56.123456+00:00' AS TIMESTAMPTZ(6)) AS TIMESTAMP_NS) AS ts;
+-------------------------------+
| ts |
+-------------------------------+
| 2024-02-29 12:34:56.123456000 |
+-------------------------------+
从 TIMESTAMP_NS 和 VARIANT 转换
将 TIMESTAMP_NS 转换为相同类型时,会精确保留原值。VARIANT 中兼容的字符串、数字、日期或时间戳值按照上文对应规则转换。带时区的时间戳值会转换到当前会话时区;不带时区的时间戳值保留日期时间字段。不兼容的 VARIANT 内容根据 CAST 模式返回 NULL 或报错。
相关转换
将 TIMESTAMP_NS 转换为 DATETIME(p) 或 TIMESTAMPTZ(p) 时,会将小数舍入到目标精度。例如,2024-02-29 12:34:56.123456789 转换为精度 6 后得到 2024-02-29 12:34:56.123457。
在比较、Join、CASE、COALESCE 或集合运算中混用 TIMESTAMP_NS 和 DATETIME 时,只要能够精确保留各输入值,Doris 会使用 TIMESTAMP_NS 作为公共类型。
错误处理
| 情况 | enable_strict_cast = true | enable_strict_cast = false | TRY_CAST |
|---|---|---|---|
| 格式或日历值非法 | 报错 | NULL | NULL |
超出 TIMESTAMP_NS 取值范围 | 报错 | NULL | NULL |
源值为 NULL | NULL | NULL | NULL |
| 不支持的源类型与目标类型组合 | 分析错误 | 分析错误 | 分析错误 |
对于字符串输入,enable_strict_cast 会选择对应的 DATETIME 严格或非严格解析规则,并控制转换失败的处理方式。对于数字输入,该变量只改变错误处理方式,两种模式使用相同的数字映射。
示例
转换纳秒精度的字符串并观察舍入结果:
SELECT
CAST('2024-02-29 12:34:56.123456' AS TIMESTAMP_NS) AS padded,
CAST('2024-02-29 12:34:56.1234567895' AS TIMESTAMP_NS) AS rounded;
+-------------------------------+-------------------------------+
| padded | rounded |
+-------------------------------+-------------------------------+
| 2024-02-29 12:34:56.123456000 | 2024-02-29 12:34:56.123456790 |
+-------------------------------+-------------------------------+
转换数字形式的日期时间:
SELECT CAST(CAST(20240229123456.1234567895 AS DECIMAL(24, 10)) AS TIMESTAMP_NS) AS ts;
+-------------------------------+
| ts |
+-------------------------------+
| 2024-02-29 12:34:56.123456790 |
+-------------------------------+
非严格模式下,非法值和超出范围的值返回 NULL:
SET enable_strict_cast = false;
SELECT
CAST('2024-02-30 00:00:00' AS TIMESTAMP_NS) AS invalid_date,
CAST('2262-04-11 23:47:16.8547758075' AS TIMESTAMP_NS) AS overflow;
+--------------+----------+
| invalid_date | overflow |
+--------------+----------+
| NULL | NULL |
+--------------+----------+