日期和时间数据类型¶
Snowflake 支持用于管理日期、时间和时间戳(日期 + 时间组合)的数据类型。Snowflake 还支持用于操控日期、时间和时间戳的字符串常量的格式。
本主题内容:
数据类型¶
Snowflake 支持以下日期和时间数据类型:
备注
对于 DATE 和 TIMESTAMP 数据,Snowflake 建议使用 1582 和 9999 之间的年份。Snowflake 可以接受此范围之外的一些年份,但由于 公历限制,应避免使用 1582 年之前的年份。
DATE¶
Snowflake 支持存储日期(没有时间元素)的单一 DATE 数据类型。
DATE 可接受最常见的日期形式(YYYY-MM-DD
、DD-MON-YYYY
等)。
此外,所有已接受的 TIMESTAMP 值都是日期的有效输入;但是 TIME 信息会被截断。
DATETIME¶
DATETIME 是 TIMESTAMP_NTZ 的别名。
TIME¶
Snowflake 支持以 HH:MI:SS
的形式存储时间的单一 TIME 数据类型。
TIME 支持用于小数秒的可选精度参数(例如 TIME(3)
)。时间精度的范围为 0(秒)到 9(纳秒)。默认精度为 9。
所有 TIME 值必须介于 00:00:00
和 23:59:59.999999999
之间。TIME 在内部存储“挂钟”时间,对 TIME 值的所有操作都是在完全不考虑时区的前提下执行的。
TIMESTAMP_LTZ、TIMESTAMP_NTZ、TIMESTAMP_TZ¶
Snowflake 支持三种时间戳变体。
- TIMESTAMP_LTZ:
TIMESTAMP_LTZ 在内部存储具有指定精度的 UTC 时间。但所有操作均在当前会话的时区中执行,由 TIMEZONE 会话参数控制。
TIMESTAMP_LTZ 的别名:
TIMESTAMPLTZ
TIMESTAMP WITH LOCAL TIME ZONE
- TIMESTAMP_NTZ:
TIMESTAMP_NTZ 在内部存储具有指定精度的“挂钟”时间。所有操作的执行均完全不考虑时区。
如果输出格式包含时区,则显示 UTC 指示符 (
Z
)。TIMESTAMP_NTZ 是 TIMESTAMP 的默认值。
TIMESTAMP_NTZ 的别名:
TIMESTAMPNTZ
TIMESTAMP WITHOUT TIME ZONE
DATETIME
- TIMESTAMP_TZ:
TIMESTAMP_TZ 在内部存储 UTC 时间及关联的 时区偏移。如未提供时区,则使用会话时区偏移。所有操作均使用特定于每条记录的时区偏移执行。
TIMESTAMP_TZ 的别名:
TIMESTAMPTZ
TIMESTAMP WITH TIME ZONE
TIMESTAMP_TZ 值根据其 UTC 时间进行比较。例如,不同时区的不同时间如果具有相同的 UTC 时间,则其比较结果为 TRUE。
SELECT '2024-01-01 00:00:00 +0000'::TIMESTAMP_TZ = '2024-01-01 01:00:00 +0100'::TIMESTAMP_TZ;
注意
TIMESTAMP_TZ 当前仅存储给定时区的 偏移,而非给定值创建时的实际 时区。这对于夏令时尤其重要,因为 UTC 不使用夏令时。
例如,如果 TIMEZONE 参数设置为 "America/Los_Angeles"
,则将值转换为给定年份的 1 月的 TIMESTAMP_TZ 会存储 -0800
的时区偏移。如果稍后为该值增加六个月,-0800
偏移将保留下来,即使在 7 月份,洛杉矶的该偏移仍为 -0700
。这是因为在创建值后,实际时区信息 ("America/Los_Angeles"
) 不再可用。下面的代码示例展示了此行为:
SELECT '2024-01-01 12:00:00'::TIMESTAMP_TZ;
+-------------------------------------+
| '2024-01-01 12:00:00'::TIMESTAMP_TZ |
|-------------------------------------|
| 2024-01-01 12:00:00.000 -0800 |
+-------------------------------------+
SELECT DATEADD(MONTH, 6, '2024-01-01 12:00:00'::TIMESTAMP_TZ);
+--------------------------------------------------------+
| DATEADD(MONTH, 6, '2024-01-01 12:00:00'::TIMESTAMP_TZ) |
|--------------------------------------------------------|
| 2024-07-01 12:00:00.000 -0800 |
+--------------------------------------------------------+
TIMESTAMP¶
Snowflake 中的 TIMESTAMP 是与一种 TIMESTAMP_* 变体关联的用户指定的别名。在使用 TIMESTAMP 的所有操作中,都会自动使用关联的 TIMESTAMP_* 变体。TIMESTAMP 数据类型从不会存储在表中。
与 TIMESTAMP 关联的 TIMESTAMP_* 变体由 TIMESTAMP_TYPE_MAPPING 会话参数指定。默认为 TIMESTAMP_NTZ。
所有时间戳变体及 TIMESTAMP 别名都支持用于小数秒的可选精度参数(例如 TIMESTAMP(3)
)。时间戳精度的范围为 0(秒)到 9(纳秒)。默认精度为 9。
时间戳示例¶
以下示例使用不同的时间戳创建表。
首先,创建一个包含 TIMESTAMP 列(已映射到 TIMESTAMP_NTZ)的表:
ALTER SESSION SET TIMESTAMP_TYPE_MAPPING = TIMESTAMP_NTZ;
CREATE OR REPLACE TABLE ts_test(ts TIMESTAMP);
DESC TABLE ts_test;
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
| name | type | kind | null? | default | primary key | unique key | check | expression | comment | policy name | privacy domain |
|------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------|
| TS | TIMESTAMP_NTZ(9) | COLUMN | Y | NULL | N | N | NULL | NULL | NULL | NULL | NULL |
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
接下来,显式使用 TIMESTAMP 变体之一 (TIMESTAMP_LTZ):
CREATE OR REPLACE TABLE ts_test(ts TIMESTAMP_LTZ);
DESC TABLE ts_test;
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
| name | type | kind | null? | default | primary key | unique key | check | expression | comment | policy name | privacy domain |
|------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------|
| TS | TIMESTAMP_LTZ(9) | COLUMN | Y | NULL | N | N | NULL | NULL | NULL | NULL | NULL |
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+----------------+
为不同时区使用 TIMESTAMP_LTZ:
CREATE OR REPLACE TABLE ts_test(ts TIMESTAMP_LTZ);
ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';
INSERT INTO ts_test VALUES('2024-01-01 16:00:00');
INSERT INTO ts_test VALUES('2024-01-02 16:00:00 +00:00');
此查询显示洛杉矶时间为 1 月 2 日 08:00(UTC 时间是 16:00):
SELECT ts, hour(ts) FROM ts_test;
+-------------------------------+----------+
| TS | HOUR(TS) |
|-------------------------------+----------|
| 2024-01-01 16:00:00.000 -0800 | 16 |
| 2024-01-02 08:00:00.000 -0800 | 8 |
+-------------------------------+----------+
接下来,注意时间会随着时区的不同而变化:
ALTER SESSION SET TIMEZONE = 'America/New_York';
SELECT ts, HOUR(ts) FROM ts_test;
+-------------------------------+----------+
| TS | HOUR(TS) |
|-------------------------------+----------|
| 2024-01-01 19:00:00.000 -0500 | 19 |
| 2024-01-02 11:00:00.000 -0500 | 11 |
+-------------------------------+----------+
创建表并使用 TIMESTAMP_NTZ:
CREATE OR REPLACE TABLE ts_test(ts TIMESTAMP_NTZ);
ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';
INSERT INTO ts_test VALUES('2024-01-01 16:00:00');
INSERT INTO ts_test VALUES('2024-01-02 16:00:00 +00:00');
请注意,来自不同时区的两个时间都转换为相同的“挂钟”时间:
SELECT ts, HOUR(ts) FROM ts_test;
+-------------------------+----------+
| TS | HOUR(TS) |
|-------------------------+----------|
| 2024-01-01 16:00:00.000 | 16 |
| 2024-01-02 16:00:00.000 | 16 |
+-------------------------+----------+
接下来,请注意更改会话时区不会影响结果:
ALTER SESSION SET TIMEZONE = 'America/New_York';
SELECT ts, HOUR(ts) FROM ts_test;
+-------------------------+----------+
| TS | HOUR(TS) |
|-------------------------+----------|
| 2024-01-01 16:00:00.000 | 16 |
| 2024-01-02 16:00:00.000 | 16 |
+-------------------------+----------+
创建表并使用 TIMESTAMP_TZ:
CREATE OR REPLACE TABLE ts_test(ts TIMESTAMP_TZ);
ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';
INSERT INTO ts_test VALUES('2024-01-01 16:00:00');
INSERT INTO ts_test VALUES('2024-01-02 16:00:00 +00:00');
请注意,1 月 1 日的记录继承了会话时区,并且“America/Los_Angeles”被转换为数字时区偏移:
SELECT ts, HOUR(ts) FROM ts_test;
+-------------------------------+----------+
| TS | HOUR(TS) |
|-------------------------------+----------|
| 2024-01-01 16:00:00.000 -0800 | 16 |
| 2024-01-02 16:00:00.000 +0000 | 16 |
+-------------------------------+----------+
接下来,请注意更改会话时区不会影响结果:
ALTER SESSION SET TIMEZONE = 'America/New_York';
SELECT ts, HOUR(ts) FROM ts_test;
+-------------------------------+----------+
| TS | HOUR(TS) |
|-------------------------------+----------|
| 2024-01-01 16:00:00.000 -0800 | 16 |
| 2024-01-02 16:00:00.000 +0000 | 16 |
+-------------------------------+----------+
支持的日历¶
Snowflake 为所有日期和时间戳使用公历。公历从 1582 年开始,但可以识别以前的年份,这一点非常重要,因为 Snowflake 不会 为了匹配儒略历而调整 1582 年之前的日期(或涉及 1582 年之前日期的计算)。UUUU
格式元素支持负数年份。
日期和时间格式¶
所有这些数据类型都接受最无歧义的日期、时间或日期 + 时间格式。请参阅 AUTO 检测支持的格式,了解 Snowflake 在 配置为自动检测格式 时可识别的格式。
您也可以 手动指定日期和时间格式。在指定格式时,可使用下表中列出的不区分大小写的元素:
格式元素 |
描述 |
---|---|
|
四位数年份。 |
|
两位数年份,由 TWO_DIGIT_CENTURY_START 会话参数控制,例如,当设置为 |
|
两位数月份( |
|
月份名称的全称或缩写。 |
|
月份名称的全称。 |
|
月份的两位数天数( |
|
星期的缩写。 |
|
两位数小时( |
|
两位数小时( |
|
上午 ( |
|
两位数分钟( |
|
两位数秒钟( |
|
精度为 ``0``(秒)至 ``9``(纳秒)的小数秒,例如 |
|
时区小时和分钟,从 UTC 开始偏移。可以用 |
|
四位数年份,格式为 ISO (link removed),负数为 BCE 年份。 |
备注
当使用仅日期格式时,关联时间假定为当天的午夜。
格式中双引号之间或上述元素以外的任何内容都会被解析/格式化,但不会被解释。
有关有效范围、位数和最佳实践的更多详细信息,请参阅 有关使用日期、时间和时间戳格式的其他信息。
使用日期和时间格式的示例¶
以下示例使用 FF
指示输出在小数秒字段中有 9 位数:
CREATE TABLE timestamp_demo_table(
t TIMESTAMP,
t_tz TIMESTAMP_TZ,
t_ntz TIMESTAMP_NTZ,
t_ltz TIMESTAMP_LTZ);
INSERT INTO timestamp_demo_table (t, t_tz, t_ntz, t_ltz) VALUES (
'2024-03-12 01:02:03.123456789',
'2024-03-12 01:02:03.123456789',
'2024-03-12 01:02:03.123456789',
'2024-03-12 01:02:03.123456789');
ALTER SESSION SET TIMESTAMP_OUTPUT_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';
ALTER SESSION SET TIMESTAMP_TZ_OUTPUT_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';
ALTER SESSION SET TIMESTAMP_NTZ_OUTPUT_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';
ALTER SESSION SET TIMESTAMP_LTZ_OUTPUT_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF';
SELECT t, t_tz, t_ntz, t_ltz
FROM timestamp_demo_table;
+-------------------------------+-------------------------------+-------------------------------+-------------------------------+
| T | T_TZ | T_NTZ | T_LTZ |
|-------------------------------+-------------------------------+-------------------------------+-------------------------------|
| 2024-03-12 01:02:03.123456789 | 2024-03-12 01:02:03.123456789 | 2024-03-12 01:02:03.123456789 | 2024-03-12 01:02:03.123456789 |
+-------------------------------+-------------------------------+-------------------------------+-------------------------------+
日期和时间常量¶
常量*(也称为 *字面量)是固定的数据值。Snowflake 支持使用字符串常量指定固定的日期、时间或时间戳值。字符串常量必须始终置于分隔符之间。Snowflake 支持使用单引号来分隔字符串常量。
例如:
DATE '2024-08-14'
TIME '10:03:56'
TIMESTAMP '2024-08-15 10:59:43'
字符串根据数据类型的输入格式解析为 DATE、TIME 或 TIMESTAMP 值,通过以下参数设置:
- DATE:
- TIME:
- TIMESTAMP:
例如,要将特定日期插入到一个表的某个列中:
CREATE TABLE t1 (d1 DATE);
INSERT INTO t1 (d1) VALUES (DATE '2024-08-15');
间隔时间常量¶
您可以使用间隔时间常量在日期、时间或时间戳之间添加或减去特定时间段。间隔时间常量使用 INTERVAL 关键字实现,具有以下语法:
{ + | - } INTERVAL '<integer> [ <date_time_part> ] [ , <integer> [ <date_time_part> ] ... ]'
与所有字符串常量一样,Snowflake 需要用单引号来括起间隔时间常量。
INTERVAL 关键字支持一个以上的整数,以及一个或多个日期或时间部分(可选)。例如:
INTERVAL '1 year'
表示一年。INTERVAL '4 years, 5 months, 3 hours'
表示四年五个月零三个小时。
如果未指定日期或时间部分,则间隔时间表示的是秒(例如,INTERVAL '2'
与 INTERVAL '2 seconds'
相同)。请注意,这与执行日期算术运算的默认时间单位不同。有关更多详细信息,请参阅 日期的简单算术运算。
有关受支持的日期和时间部分的列表,请参阅 时间间隔支持的日期和时间部分。
备注
间隔时间增量的顺序很重要。增量按列出的顺序加减。例如:
INTERVAL '1 year, 1 day'
首先加或减一年,然后加或减一天。INTERVAL '1 day, 1 year'
首先加或减一天,然后加或减一年。
排序差异可能会影响受日历事件(如闰年)影响的计算:
SELECT TO_DATE ('2019-02-28') + INTERVAL '1 day, 1 year';
+---------------------------------------------------+ | TO_DATE ('2019-02-28') + INTERVAL '1 DAY, 1 YEAR' | |---------------------------------------------------| | 2020-03-01 | +---------------------------------------------------+
SELECT TO_DATE ('2019-02-28') + INTERVAL '1 year, 1 day';
+---------------------------------------------------+ | TO_DATE ('2019-02-28') + INTERVAL '1 YEAR, 1 DAY' | |---------------------------------------------------| | 2020-02-29 | +---------------------------------------------------+
INTERVAL 不是数据类型(也就是说,您不能将表列定义为数据类型 INTERVAL)。间隔时间只能用于日期、时间和时间戳算术运算。
您不能将间隔时间用于 SQL 变量。例如,以下查询会返回错误:
SET v1 = '1 year'; SELECT TO_DATE('2023-04-15') + INTERVAL $v1;
间隔时间支持的日期和时间部分¶
INTERVAL 关键字支持将以下日期和时间部分作为实参(不区分大小写):
日期或时间部分 |
缩写/变体 |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
间隔时间示例¶
为特定日期加上一个年份间隔时间:
SELECT TO_DATE('2023-04-15') + INTERVAL '1 year';
+-------------------------------------------+
| TO_DATE('2023-04-15') + INTERVAL '1 YEAR' |
|-------------------------------------------|
| 2024-04-15 |
+-------------------------------------------+
将 3 小时 18 分钟的间隔时间添加到特定时间:
SELECT TO_TIME('04:15:29') + INTERVAL '3 hours, 18 minutes';
+------------------------------------------------------+
| TO_TIME('04:15:29') + INTERVAL '3 HOURS, 18 MINUTES' |
|------------------------------------------------------|
| 07:33:29 |
+------------------------------------------------------+
在 CURRENT_TIMESTAMP 函数的输出中加上一个复杂的时间间隔:
SELECT CURRENT_TIMESTAMP + INTERVAL
'1 year, 3 quarters, 4 months, 5 weeks, 6 days, 7 minutes, 8 seconds,
1000 milliseconds, 4000000 microseconds, 5000000001 nanoseconds'
AS complex_interval1;
+-------------------------------+
| COMPLEX_INTERVAL1 |
|-------------------------------|
| 2026-11-07 18:07:19.875000001 |
+-------------------------------+
为特定日期加上一个复杂时间间隔(日期/时间部分使用缩写表示法):
SELECT TO_DATE('2025-01-17') + INTERVAL
'1 y, 3 q, 4 mm, 5 w, 6 d, 7 h, 9 m, 8 s,
1000 ms, 445343232 us, 898498273498 ns'
AS complex_interval2;
+-------------------------------+
| COMPLEX_INTERVAL2 |
|-------------------------------|
| 2027-03-30 07:31:32.841505498 |
+-------------------------------+
查询员工信息表,返回过去两年三个月内录用的员工姓名:
SELECT name, hire_date
FROM employees
WHERE hire_date > CURRENT_DATE - INTERVAL '2 y, 3 month';
从名为 t1
的表中筛选出名为 ts
的 TIMESTAMP 列,并为每个返回值加上四秒:
SELECT ts + INTERVAL '4 seconds'
FROM t1
WHERE ts > TO_TIMESTAMP('2024-04-05 01:02:03');
日期的简单算术运算¶
除了使用间隔时间常量为日期、时间和时间戳进行加减之外,您还能以 { + | - }
integer
的形式对 DATE 值进行天数的加减,其中 integer
指定要加/减的天数。
备注
TIME 和 TIMESTAMP 值尚不支持简单算术运算。
日期算术运算示例¶
为特定日期加一天:
SELECT TO_DATE('2024-04-15') + 1;
+---------------------------+
| TO_DATE('2024-04-15') + 1 |
|---------------------------|
| 2024-04-16 |
+---------------------------+
为特定日期减四天:
SELECT TO_DATE('2024-04-15') - 4;
+---------------------------+
| TO_DATE('2024-04-15') - 4 |
|---------------------------|
| 2024-04-11 |
+---------------------------+
查询名为 employees
的表,并返回已离职但受雇时间超过 365 天的人员的姓名:
SELECT name
FROM employees
WHERE end_date > start_date + 365;