日期和时间数据类型¶
Snowflake 支持用于管理日期、时间和时间戳(日期 + 时间组合)的数据类型。Snowflake 还支持用于操控日期、时间和时间戳的字符串常量的格式。
数据类型¶
Snowflake 支持以下日期和时间数据类型:
备注
对于 DATE 和 TIMESTAMP 数据,Snowflake 建议使用 1582 和 9999 之间的年份。Snowflake 可以接受此范围之外的一些年份,但由于 公历限制,应避免使用 1582 年之前的年份。
DATE¶
Snowflake 支持存储日期(没有时间元素)的单一 DATE 数据类型。
DATE 可接受最常见的日期形式(YYYY-MM-DD、DD-MON-YYYY 等)。
此外,所有已接受的 TIMESTAMP 值都是日期的有效输入,但是 TIME 信息会被截断。
DATETIME¶
DATETIME is synonymous with 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 internally stores UTC values with a specified precision. However, all operations are performed in the current session's time zone, controlled by the TIMEZONE session parameter.
Synonymous with TIMESTAMP_LTZ:
TIMESTAMPLTZ
TIMESTAMP WITH LOCAL TIME ZONE
- TIMESTAMP_NTZ:
TIMESTAMP_NTZ 在内部存储具有指定精度的“挂钟”时间。所有操作的执行均完全不考虑时区。
如果输出格式包含时区,则显示 UTC 指示符 (
Z)。TIMESTAMP_NTZ 是 TIMESTAMP 的默认值。
Synonymous with TIMESTAMP_NTZ:
TIMESTAMPNTZ
TIMESTAMP WITHOUT TIME ZONE
DATETIME
- TIMESTAMP_TZ:
TIMESTAMP_TZ internally stores UTC values together with an associated time zone offset. When a time zone isn't provided, the session time zone offset is used. All operations are performed with the time zone offset specific to each record.
Synonymous with 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 在 配置为自动检测格式 时可识别的格式。
您也可以 手动指定日期和时间格式。在指定格式时,可使用下表中列出的不区分大小写的元素:
格式元素 |
描述 |
|---|---|
|
Four-digit [1] year. |
|
Two-digit [1] year, controlled by the TWO_DIGIT_CENTURY_START session parameter. For example, when set to |
|
Two-digit [1] month ( |
|
Abbreviated month name [2]. |
|
Full month name [2]. |
|
Two-digit [1] day of month ( |
|
星期的缩写。 |
|
Two digits [1] for hour ( |
|
Two digits [1] for hour ( |
|
上午 ( |
|
Two digits [1] for minute ( |
|
Two digits [1] for second ( |
|
精度为 ``0``(秒)至 ``9``(纳秒)的小数秒,例如 |
|
Two-digit [1] time zone hour and minute, offset from UTC. Can be prefixed by |
|
四位数年份,格式为 ISO (link removed),负数为 BCE 年份。 |
[1] 位数描述了将值序列化为文本时生成的输出。解析文本时,Snowflake 最多可接受的指定位数。例如,天数可以是一位或两位数。
[2] For the MON format element, the output produced when serializing values to text is the abbreviated month name. For the MMMM format element, the output produced when serializing values to text is the full month name. When parsing text, Snowflake accepts the three-digit abbreviation or the full month name for both MON and MMMM. For example, "January" or "Jan", "February" or "Feb", and so on are accepted when parsing text.
备注
当使用仅日期格式时,关联时间假定为当天的午夜。
格式中双引号之间或上述元素以外的任何内容都会被解析/格式化,但不会被解释。
有关有效范围、位数和最佳实践的更多详细信息,请参阅 有关使用日期、时间和时间戳格式的其他信息。
使用日期和时间格式的示例¶
以下示例使用 FF 指示输出在小数秒字段中有 9 位数:
CREATE OR REPLACE TABLE timestamp_demo_table(
tstmp TIMESTAMP,
tstmp_tz TIMESTAMP_TZ,
tstmp_ntz TIMESTAMP_NTZ,
tstmp_ltz TIMESTAMP_LTZ);
INSERT INTO timestamp_demo_table (tstmp, tstmp_tz, tstmp_ntz, tstmp_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 tstmp, tstmp_tz, tstmp_ntz, tstmp_ltz
FROM timestamp_demo_table;
+-------------------------------+-------------------------------+-------------------------------+-------------------------------+
| TSTMP | TSTMP_TZ | TSTMP_NTZ | TSTMP_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;