日期和时间数据类型

本主题介绍 Snowflake 中支持用于管理日期、时间和时间戳(日期 + 时间组合)的数据类型。此外还介绍了用于操控日期、时间和时间戳的字符串常量支持的格式。

本主题内容:

数据类型

DATE

Snowflake 支持存储日期(没有时间元素)的单一 DATE 数据类型。

DATE 可接受最常见的日期形式(YYYY-MM-DDDD-MON-YYYY 等)。

此外,所有已接受的 TIMESTAMP 值都是日期的有效输入;但是 TIME 信息会被截断。

对于 DATE 和 TIMESTAMP 数据,Snowflake 建议使用 1582 和 9999 之间的年份。Snowflake 可以接受此范围之外的一些年份,但由于 公历限制,应避免使用 1582 年之前的年份。

DATETIME

DATETIME 是 TIMESTAMP_NTZ 的别名。

TIME

Snowflake 支持以 HH:MI:SS 的形式存储时间的单一 TIME 数据类型。

TIME 支持用于小数秒的可选精度参数,例如 TIME(3)。时间精度的范围为 0(秒)到 9(纳秒)。默认精度为 9。

所有 TIME 值必须介于 00:00:0023:59:59.999999999 之间。TIME 在内部存储“挂钟”时间,对 TIME 值的所有操作都是在完全不考虑时区的前提下执行的。

TIMESTAMP

Snowflake 中的 TIMESTAMP 是与一种 TIMESTAMP_* 变体关联的用户指定的别名。在使用 TIMESTAMP 的所有操作中,都会自动使用关联的 TIMESTAMP_* 变体。TIMESTAMP 数据类型从不会存储在表中。

与 TIMESTAMP 关联的 TIMESTAMP_* 变体由 TIMESTAMP_TYPE_MAPPING 会话参数指定。默认为 TIMESTAMP_NTZ。

对于 DATE 和 TIMESTAMP 数据,Snowflake 建议使用 1582 和 9999 之间的年份。Snowflake 可以接受此范围之外的一些年份,但由于 公历限制,应避免使用 1582 年之前的年份。

所有时间戳变体及 TIMESTAMP 别名都支持用于小数秒的可选精度参数,例如 TIMESTAMP(3)。时间戳精度的范围为 0(秒)到 9(纳秒)。默认精度为 9。

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

TIMESTAMP_TZ:

TIMESTAMP_TZ 在内部存储 UTC 时间及关联的 时区偏移。如未提供时区,则使用会话时区偏移。所有操作均使用特定于每条记录的时区偏移执行。

TIMESTAMP_TZ 的别名:

  • TIMESTAMPTZ

  • TIMESTAMP WITH TIME ZONE

TIMESTAMP_TZ 值根据其 UTC 时间进行比较。例如,不同时区的不同时间如果具有相同的 UTC 时间,则其比较结果为 TRUE。

select '2021-01-01 00:00:00 +0000'::timestamp_tz = '2021-01-01 01:00:00 +0100'::timestamp_tz;
Copy

注意

TIMESTAMP_TZ 当前仅存储给定时区的 偏移,而非给定值创建时的实际 时区。在处理夏令时的时候,这一点尤为重要,因为 UTC 不使用夏令时。

例如,如果 TIMEZONE 参数设置为 "America/Los_Angeles",则将值转换为给定年份的 1 月的 TIMESTAMP_TZ 会存储 -0800 的时区偏移。如果稍后为该值增加 6 个月,-0800 偏移将保留下来,即使在 7 月份,洛杉矶的该偏移仍为 -0700。这是因为在创建值后,实际时区信息 ("America/Los_Angeles") 不再可用。下面的代码示例展示了此行为:

SELECT '2017-01-01 12:00:00'::TIMESTAMP_TZ;

-------------------------------------+
 '2017-01-01 12:00:00'::TIMESTAMP_TZ |
-------------------------------------+
 2017-01-01 12:00:00 -0800           |
-------------------------------------+

SELECT DATEADD(MONTH, 6, '2017-01-01 12:00:00'::TIMESTAMP_TZ);

--------------------------------------------------------+
 DATEADD(MONTH, 6, '2017-01-01 12:00:00'::TIMESTAMP_TZ) |
--------------------------------------------------------+
 2017-07-01 12:00:00 -0800                              |
--------------------------------------------------------+
Copy

时间戳示例

使用不同的时间戳创建表:

-- First, use TIMESTAMP (mapped to 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 |
|------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------|
| TS   | TIMESTAMP_NTZ(9) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    |
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+

-- Next, explicitly use one of the TIMESTAMP variations (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 |
|------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------|
| TS   | TIMESTAMP_LTZ(9) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    |
+------+------------------+--------+-------+---------+-------------+------------+-------+------------+---------+
Copy

为不同时区使用 TIMESTAMP_LTZ:

CREATE OR REPLACE TABLE ts_test(ts timestamp_ltz);

ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';

INSERT INTO ts_test values('2014-01-01 16:00:00');
INSERT INTO ts_test values('2014-01-02 16:00:00 +00:00');

-- Note that the time for January 2nd is 08:00 in Los Angeles (which is 16:00 in UTC)

SELECT ts, hour(ts) FROM ts_test;

+---------------------------------+----------+
| TS                              | HOUR(TS) |
|---------------------------------+----------|
| Wed, 01 Jan 2014 16:00:00 -0800 |       16 |
| Thu, 02 Jan 2014 08:00:00 -0800 |        8 |
+---------------------------------+----------+

-- Next, note that the times change with a different time zone

ALTER SESSION SET TIMEZONE = 'America/New_York';

SELECT ts, hour(ts) FROM ts_test;

+---------------------------------+----------+
| TS                              | HOUR(TS) |
|---------------------------------+----------|
| Wed, 01 Jan 2014 19:00:00 -0500 |       19 |
| Thu, 02 Jan 2014 11:00:00 -0500 |       11 |
+---------------------------------+----------+
Copy

使用 TIMESTAMP_NTZ:

CREATE OR REPLACE TABLE ts_test(ts timestamp_ntz);

ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';

INSERT INTO ts_test values('2014-01-01 16:00:00');
INSERT INTO ts_test values('2014-01-02 16:00:00 +00:00');

-- Note that both times from different time zones are converted to the same "wallclock" time

SELECT ts, hour(ts) FROM ts_test;

+---------------------------+----------+
| TS                        | HOUR(TS) |
|---------------------------+----------|
| Wed, 01 Jan 2014 16:00:00 |       16 |
| Thu, 02 Jan 2014 16:00:00 |       16 |
+---------------------------+----------+

-- Next, note that changing the session time zone does not influence the results

ALTER SESSION SET TIMEZONE = 'America/New_York';

SELECT ts, hour(ts) FROM ts_test;

+---------------------------+----------+
| TS                        | HOUR(TS) |
|---------------------------+----------|
| Wed, 01 Jan 2014 16:00:00 |       16 |
| Thu, 02 Jan 2014 16:00:00 |       16 |
+---------------------------+----------+
Copy

使用 TIMESTAMP_TZ:

CREATE OR REPLACE TABLE ts_test(ts timestamp_tz);

ALTER SESSION SET TIMEZONE = 'America/Los_Angeles';

INSERT INTO ts_test values('2014-01-01 16:00:00');
INSERT INTO ts_test values('2014-01-02 16:00:00 +00:00');

-- Note that the January 1st record inherited the session time zone,
-- and "America/Los_Angeles" was converted into a numeric time zone offset

SELECT ts, hour(ts) FROM ts_test;

+---------------------------------+----------+
| TS                              | HOUR(TS) |
|---------------------------------+----------|
| Wed, 01 Jan 2014 16:00:00 -0800 |       16 |
| Thu, 02 Jan 2014 16:00:00 +0000 |       16 |
+---------------------------------+----------+

-- Next, note that changing the session time zone does not influence the results

ALTER SESSION SET TIMEZONE = 'America/New_York';

SELECT ts, hour(ts) FROM ts_test;

+---------------------------------+----------+
| TS                              | HOUR(TS) |
|---------------------------------+----------|
| Wed, 01 Jan 2014 16:00:00 -0800 |       16 |
| Thu, 02 Jan 2014 16:00:00 +0000 |       16 |
+---------------------------------+----------+
Copy

支持的日历

Snowflake 为所有日期和时间戳使用公历。公历从 1582 年开始,但可以识别以前的年份,这一点非常重要,因为 Snowflake 不会 为了匹配儒略历而调整 1582 年之前的日期(或涉及 1582 年之前日期的计算)。UUUU 格式元素支持负数年份。

日期和时间格式

所有这些数据类型都接受最合理、无歧义的日期、时间或日期 + 时间格式。请参阅 AUTO 检测支持的格式,了解 Snowflake 在 配置为自动检测格式 时可识别的格式。

您也可以 手动指定日期和时间格式。在指定格式时,可使用下表中列出的不区分大小写的元素:

格式元素

描述

YYYY

四位数年份。

YY

两位数年份,由 TWO_DIGIT_CENTURY_START 会话参数控制,例如,当设置为 1980 时,7980 这两个值将分别解析为 20791980

MM

两位数月份(01 = 一月,以此类推)。

MON

月份名称的全称或缩写。

MMMM

月份名称的全称。

DD

两位数日期(01 至 31)。

DY

星期的缩写。

HH24

两位数小时(00 至 23)。不能 指定 AM / PM

HH12

两位数小时(01 至 12)。可以指定 AM/PM

AMPM

上午 (am)/下午 (pm)。仅可用于 HH12不能 用于 HH24)。

MI

两位数分钟(00 至 59)。

SS

两位数秒钟(00 至 59)。

FF[0-9]

精度为 0(秒)至 9(纳秒)的小数秒,例如 FFFF0FF3FF9。指定 FF 等同于 FF9 (纳秒)。

TZH:TZMTZHTZMTZH

时区小时和分钟,从 UTC 开始偏移。可以用 +/- 作为符号前缀。

UUUU

四位数年份,格式为 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 (
    '2020-03-12 01:02:03.123456789',
    '2020-03-12 01:02:03.123456789',
    '2020-03-12 01:02:03.123456789',
    '2020-03-12 01:02:03.123456789'
    );
Copy
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';
Copy
SELECT t, t_tz, t_ntz, t_ltz 
    FROM timestamp_demo_table;
+-------------------------------+-------------------------------+-------------------------------+-------------------------------+
| T                             | T_TZ                          | T_NTZ                         | T_LTZ                         |
|-------------------------------+-------------------------------+-------------------------------+-------------------------------|
| 2020-03-12 01:02:03.123456789 | 2020-03-12 01:02:03.123456789 | 2020-03-12 01:02:03.123456789 | 2020-03-12 01:02:03.123456789 |
+-------------------------------+-------------------------------+-------------------------------+-------------------------------+
Copy

日期和时间常量

常量*(也称为 *字面量)是指固定的数据值。Snowflake 支持使用字符串常量指定固定的日期、时间或时间戳值。字符串常量必须始终置于分隔符之间。Snowflake 支持使用单引号来分隔字符串常量。

例如:

date '2010-09-14'
time '10:03:56'
timestamp '2009-09-15 10:59:43'
Copy

字符串根据数据类型的输入格式解析为 DATE、TIME 或 TIMESTAMP 值,通过以下参数设置:

DATE:

DATE_INPUT_FORMAT

TIME:

TIME_INPUT_FORMAT

TIMESTAMP:

TIMESTAMP_INPUT_FORMAT

例如,要将特定日期插入到一个表的某个列中:

CREATE TABLE t1 (d1 DATE);

INSERT INTO t1 (d1) VALUES (DATE '2011-10-29');
Copy

间隔时间常量

您可以使用间隔时间常量在日期、时间或时间戳之间添加或减去特定时间段。间隔时间常量使用 INTERVAL 关键字实现,具有以下语法:

{ + | - } INTERVAL '<integer> [ <date_time_part> ] [ , <integer> [ <date_time_part> ] ... ]'
Copy

与所有字符串常量一样,Snowflake 需要用单引号来括起间隔时间常量。

INTERVAL 关键字支持一个以上的整数,以及一个或多个日期或时间部分(可选)。例如:

  • INTERVAL '1 YEAR' 代表 1 年。

  • INTERVAL '4 years, 5 months, 3 hours' 代表 4 年 5 个月 3 小时。

如果未指定日期或时间部分,则间隔时间表示的是秒(例如,INTERVAL '2 seconds'INTERVAL '2' 相同)。请注意,这与执行日期算术运算的默认时间单位不同。有关更多详细信息,请参阅 :ref:`label-simple_date_arithmetic`(本主题内容)。

有关受支持的日期和时间部分的列表,请参阅 时间间隔支持的日期和时间部分 (本主题内容)。

备注

  • 间隔时间增量的顺序很重要。增量按列出的顺序加减。例如:

    • 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                                        |
    +---------------------------------------------------+
    
    Copy
  • INTERVAL 不是数据类型(即您不能将表列定义为 INTERVAL 数据类型)。间隔时间只能用于日期、时间和时间戳算术运算。

间隔时间支持的日期和时间部分

INTERVAL 关键字支持将以下日期和时间部分作为实参(不区分大小写):

日期或时间部分

缩写/变体

year

yyyyyyyyyyyryearsyrs

quarter

qqtrqtrsquarters

month

mmmonmonsmonths

week

wwkweekofyearwoywyweeks

day

ddddaysdayofmonth

hour

hhhhrhourshrs

minute

mmiminminutesmins

second

ssecsecondssecs

millisecond

msmsecmilliseconds

microsecond

ususecmicroseconds

nanosecond

nsnsecnanosecnsecondnanosecondsnanosecsnseconds

间隔时间示例

为特定日期加上一个年份间隔时间:

select to_date('2018-04-15') + INTERVAL '1 year';

+-------------------------------------------+
| TO_DATE('2018-04-15') + INTERVAL '1 YEAR' |
|-------------------------------------------|
| 2019-04-15                                |
+-------------------------------------------+
Copy

为特定时间加上 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                                             |
+------------------------------------------------------+
Copy

在 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_INTERVAL              |
|-------------------------------|
| 2020-12-28 08:08:01.325 -0800 |
+-------------------------------+
Copy

为特定日期加上一个复杂时间间隔(日期/时间部分使用缩写表示法):

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.841 |
+-------------------------+
Copy

查询员工信息表,返回过去 2 年 3 个月内录用的员工姓名:

select name, hire_date from employees where hire_date > current_date - INTERVAL '2 y, 3 month';
Copy

从名为 tl 的表中筛选出名为 ts 的时间戳列,并为每个返回值加上 4 秒:

select ts + INTERVAL '4 seconds' from t1 where ts > to_timestamp('2014-04-05 01:02:03');
Copy

日期的简单算术运算

除了使用间隔时间常量为日期、时间和时间戳进行加减之外,Snowflake 还支持以 { + | - } <integer> 的形式对 DATE 值进行天数的基本加减运算,其中 <integer> 指定要加/减的天数。

备注

TIME 和 TIMESTAMP 值尚不支持简单算术运算。

日期算术运算示例

为特定日期加 1 天:

select to_date('2018-04-15') + 1;

+---------------------------+
| TO_DATE('2018-04-15') + 1 |
|---------------------------|
| 2018-04-16                |
+---------------------------+
Copy

为特定日期减 4 天:

select to_date('2018-04-15') - 4;

+---------------------------+
| TO_DATE('2018-04-15') - 4 |
|---------------------------|
| 2018-04-11                |
+---------------------------+
Copy

查询名为 employees 的表,并返回已离职但受雇时间超过 365 天的人员的姓名:

select name from employees where end_date > start_date + 365;
Copy
语言: 中文