跳到主要内容

日期与时间

引入或更新于:v1.2.648

日期与时间数据类型

名称别名存储大小分辨率最小值最大值描述
DATE4 字节1000-01-019999-12-31YYYY-MM-DD
TIMESTAMPDATETIME8 字节微秒1000-01-01 00:00:009999-12-31 23:59:59.999999 UTCYYYY-MM-DD hh:mm:ss[.fraction],精度可达微秒(6 位小数)

示例

CREATE TABLE test_dt
(
date DATE,
ts TIMESTAMP
);
DESC test_dt;

结果:

┌────────────────────────────────────────────────┐
│ 字段 │ 类型 │ 可为空 │ 默认值 │ 额外 │
├────────┼───────────┼────────┼─────────┼────────┤
│ date │ DATE │ 是 │ NULL │ │
│ ts │ TIMESTAMP │ 是 │ NULL │ │
└────────────────────────────────────────────────┘

TIMESTAMP 值可以选择性地包含一个尾部的秒小数部分,精度可达微秒(6 位小数)。

-- 向表中插入值
INSERT INTO test_dt
VALUES
('2022-04-07', '2022-04-07 01:01:01.123456'),
('2022-04-08', '2022-04-08 01:01:01');

SELECT *
FROM test_dt;

结果:

┌─────────────────────────────────────────────┐
│ date │ ts │
├────────────────┼────────────────────────────┤
│ 2022-04-07 │ 2022-04-07 01:01:01.123456 │
│ 2022-04-08 │ 2022-04-08 01:01:01 │
└─────────────────────────────────────────────┘

Databend 识别多种格式的 TIMESTAMP 值。

-- 创建一个表来测试不同的时间戳格式
CREATE TABLE test_formats (
id INT,
a TIMESTAMP
);

-- 插入不同格式的时间戳值
INSERT INTO test_formats
VALUES
(1, '2022-01-01 02:00:11'),
(2, '2022-01-02T02:00:22'),
(3, '2022-02-02T04:00:03+00:00'),
(4, '2022-02-03');
SELECT *
FROM test_formats;

结果:

┌───────────────────────────────────────┐
│ id │ a │
├─────────────────┼─────────────────────┤
│ 1 │ 2022-01-01 02:00:11 │
│ 2 │ 2022-01-02 02:00:22 │
│ 3 │ 2022-02-02 04:00:03 │
│ 4 │ 2022-02-03 00:00:00 │
└───────────────────────────────────────┘

Databend 会根据当前时区自动调整并显示 TIMESTAMP 值。

-- 创建一个表来测试带有时区调整的时间戳值
CREATE TABLE test_tz (
id INT,
t TIMESTAMP
);

-- 设置时区为 UTC
SET timezone = 'UTC';

-- 插入考虑不同时区的时间戳值
INSERT INTO test_tz
VALUES
(1, '2022-02-03T03:00:00'),
(2, '2022-02-03T03:00:00+08:00'),
(3, '2022-02-03T03:00:00-08:00'),
(4, '2022-02-03'),
(5, '2022-02-03T03:00:00+09:00'),
(6, '2022-02-03T03:00:00+06:00');
SELECT *
FROM test_tz;

结果:

┌───────────────────────────────────────┐
│ id │ t │
├─────────────────┼─────────────────────┤
│ 1 │ 2022-02-03 03:00:00 │
│ 2 │ 2022-02-02 19:00:00 │
│ 3 │ 2022-02-03 11:00:00 │
│ 4 │ 2022-02-03 00:00:00 │
│ 5 │ 2022-02-02 18:00:00 │
│ 6 │ 2022-02-02 21:00:00 │
└───────────────────────────────────────┘
-- 将时区更改为 Asia/Shanghai
SET timezone = 'Asia/Shanghai';

-- 使用新的时区设置从表中选择数据
SELECT *
FROM test_tz;

结果:

┌───────────────────────────────────────┐
│ id │ t │
├─────────────────┼─────────────────────┤
│ 1 │ 2022-02-03 11:00:00 │
│ 2 │ 2022-02-03 03:00:00 │
│ 3 │ 2022-02-03 19:00:00 │
│ 4 │ 2022-02-03 08:00:00 │
│ 5 │ 2022-02-03 02:00:00 │
│ 6 │ 2022-02-03 05:00:00 │
└───────────────────────────────────────┘

函数

参见日期与时间函数

处理夏令时调整

在某些地区,会观察到夏令时。在夏令时开始的那一天,时钟会向前调整一小时。Databend 通过 enable_dst_hour_fix 设置来管理夏令时调整。当启用时,Databend 会自动将时间提前一小时(例如,2:10 AM 将被处理为 3:10 AM)。

例如,多伦多的夏令时于 2024 年 3 月 10 日凌晨 2:00 开始。因此,当天 2:00 AM 到 3:00 AM 之间的时间不存在。Databend 依赖 Chrono 来确定每个时区的夏令时。如果提供了此范围内的某个时间,Databend 将返回错误:

SET timezone = 'America/Toronto';

SELECT to_datetime('2024-03-10 02:01:00');
error: APIError: ResponseError with 1006: cannot parse to type `TIMESTAMP`. BadArguments. Code: 1006, Text = unexpected argument. while evaluating function `to_timestamp('2024-03-10 02:01:00')` in expr `to_timestamp('2024-03-10 02:01:00')`

要修复此类错误,您可以启用 enable_dst_hour_fix 设置以将时间提前一小时:

SET enable_dst_hour_fix = 1;

SELECT to_datetime('2024-03-10 02:01:00');

┌────────────────────────────────────┐
│ to_datetime('2024-03-10 02:01:00')
├────────────────────────────────────┤
2024-03-10 03:01:00
└────────────────────────────────────┘

处理无效值

Databend 会自动将无效的日期或时间戳值转换为其最小有效等效值,日期为 1000-01-01,时间戳为 1000-01-01 00:00:00,确保在处理超出范围或格式错误的日期和时间戳时的一致性。

示例:

-- 尝试将最大日期加一天,超出有效范围。
-- 结果:返回 DateMIN (1000-01-01) 而不是错误。
SELECT ADD_DAYS(TO_DATE('9999-12-31'), 1);

┌────────────────────────────────────┐
│ add_days(to_date('9999-12-31'), 1)
├────────────────────────────────────┤
1000-01-01
└────────────────────────────────────┘
-- 尝试从最小日期减去一分钟,这将无效。
-- 结果:返回 DateMIN (1000-01-01 00:00:00),确保结果的稳定性。
SELECT SUBTRACT_MINUTES(TO_DATE('1000-01-01'), 1);

┌────────────────────────────────────────────┐
│ subtract_minutes(to_date('1000-01-01'), 1)
├────────────────────────────────────────────┤
1000-01-01 00:00:00
└────────────────────────────────────────────┘

格式化日期和时间

在 Databend 中,某些日期和时间函数如 TO_DATETO_TIMESTAMP 要求您指定日期和时间值的所需格式。为了处理日期和时间的格式化,Databend 使用了 chrono::format::strftime 模块,这是 Rust 中 chrono 库提供的标准模块。该模块能够精确控制日期和时间的格式化。以下内容摘自 https://docs.rs/chrono/latest/chrono/format/strftime/index.html

格式符示例描述
日期格式符:
%Y2001完整的格里高利历年份,补零至4位。chrono支持从-262144到262143的年份。注意:公元前1年之前或公元9999年之后的年份,需要在前面加上符号(+/-)。
%C20格里高利历年份除以100,补零至2位。
%y01格里高利历年份模100,补零至2位。
%m07月份数字(01–12),补零至2位。
%bJul缩写的月份名称。始终为3个字母。
%BJuly完整的月份名称。在解析时也接受相应的缩写。
%hJul同%b。
%d08日期数字(01–31),补零至2位。
%e8同%d,但用空格填充。同%_d。
%aSun缩写的星期名称。始终为3个字母。
%ASunday完整的星期名称。在解析时也接受相应的缩写。
%w0星期日 = 0,星期一 = 1,…,星期六 = 6。
%u7星期一 = 1,星期二 = 2,…,星期日 = 7。(ISO 8601)
%U28从星期日开始的周数(00–53),补零至2位。
%W27同%U,但第一周从该年的第一个星期一开始。
%G2001同%Y,但使用ISO 8601周日期中的年份数字。
%g01同%y,但使用ISO 8601周日期中的年份数字。
%V27同%U,但使用ISO 8601周日期中的周数(01–53)。
%j189一年中的第几天(001–366),补零至3位。
%D07/08/01月-日-年格式。同%m/%d/%y。
%x07/08/01本地日期表示(例如,12/31/99)。
%F2001-07-08年-月-日格式(ISO 8601)。同%Y-%m-%d。
%v8-Jul-2001日-月-年格式。同%e-%b-%Y。
时间格式符:
%H00小时数字(00–23),补零至2位。
%k0同%H,但用空格填充。同%_H。
%I1212小时制的小时数字(01–12),补零至2位。
%l12同%I,但用空格填充。同%_I。
%Pam12小时制中的am或pm。
%pAM12小时制中的AM或PM。
%M34分钟数字(00–59),补零至2位。
%S60秒数字(00–60),补零至2位。
%f026490000自上一整秒以来的纳秒级小数秒。
%.f.026490类似于.%f,但左对齐。这些都会消耗前导点。
%.3f.026类似于.%f,但左对齐且固定长度为3。
%.6f.026490类似于.%f,但左对齐且固定长度为6。
%.9f.026490000类似于.%f,但左对齐且固定长度为9。
%3f026类似于%.3f,但没有前导点。
%6f026490类似于%.6f,但没有前导点。
%9f026490000类似于%.9f,但没有前导点。
%R00:34小时-分钟格式。同%H:%M。
%T00:34:60小时-分钟-秒格式。同%H:%M:%S。
%X00:34:60本地时间表示(例如,23:13:48)。
%r12:34:60 AM12小时制的小时-分钟-秒格式。同%I:%M:%S %p。
时区格式符:
%ZACST本地时区名称。在解析时跳过所有非空白字符。
%z+0930本地时间与UTC的偏移量(UTC为+0000)。
%:z+09:30同%z,但带有冒号。
%::z+09:30:00本地时间与UTC的偏移量,带秒数。
%:::z+09本地时间与UTC的偏移量,不带分钟数。
%#z+09仅解析:同%z,但允许分钟数缺失或存在。
日期和时间格式符:
%cSun Jul 8 00:34:60 2001本地日期和时间(例如,Thu Mar 3 23:05:25 2005)。
%+2001-07-08T00:34:60.026490+09:30ISO 8601 / RFC 3339 日期和时间格式。
%s994518299UNIX时间戳,自1970-01-01 00:00 UTC以来的秒数。Databend建议先将整数字符串转换为整数,而不是使用此格式符。有关示例,请参见将整数转换为时间戳
特殊格式符:
%t字面制表符(\t)。
%n字面换行符(\n)。
%%字面百分号。

可以覆盖数字说明符 %? 的默认填充行为。对于其他说明符,这是不允许的,会导致 BAD_FORMAT 错误。

修饰符描述
%-?抑制任何填充,包括空格和零。(例如:%j = 012,%-j = 12)
%_?使用空格作为填充。(例如:%j = 012,%_j = 12)
%0?使用零作为填充。(例如:%e = 9,%0e = 09)
  • %C, %y: 这是向下取整的除法,因此公元前100年(年份编号为-99)将分别打印为-1和99。

  • %U: 第1周从该年的第一个星期日开始。在第一个星期日之前的日子可能有第0周。

  • %G, %g, %V: 第1周是该年中至少有4天的第一周。第0周不存在,因此应与%G或%g一起使用。

  • %S: 它考虑了闰秒,因此可能会出现60。

  • %f, %.f, %.3f, %.6f, %.9f, %3f, %6f, %9f: 默认的%f是右对齐的,并且总是用零填充到9位,以与glibc等兼容,因此它总是计算自上一整秒以来的纳秒数。例如,上一秒后的7毫秒将打印为007000000,解析7000000将产生相同的结果。

    变体%.f是左对齐的,并根据精度打印0、3、6或9位小数。例如,上一秒后的70毫秒在%.f下将打印为.070(注意:不是.07),解析.07、.070000等将产生相同的结果。请注意,如果小数部分为零或下一个字符不是.,它们可能不打印或读取任何内容。

    变体%.3f、%.6f和%.9f是左对齐的,并根据f前面的数字打印3、6或9位小数。例如,上一秒后的70毫秒在%.3f下将打印为.070(注意:不是.07),解析.07、.070000等将产生相同的结果。请注意,如果小数部分为零或下一个字符不是.,它们可能不读取任何内容,但会以指定的长度打印。

    变体%3f、%6f和%9f是左对齐的,并根据f前面的数字打印3、6或9位小数,但没有前导点。例如,上一秒后的70毫秒在%3f下将打印为070(注意:不是07),解析07、070000等将产生相同的结果。请注意,如果小数部分为零,它们可能不读取任何内容。

  • %Z: 偏移量不会从解析的数据中填充,也不会进行验证。时区完全被忽略。类似于glibc strptime对此格式代码的处理。

    无法可靠地从缩写转换为偏移量,例如CDT可以表示北美中部夏令时或中国夏令时。

  • %+: 与%Y-%m-%dT%H:%M:%S%.f%:z相同,即秒的0、3、6或9位小数和时区偏移中的冒号。

    此格式还支持用Z或UTC代替%:z。它们等同于+00:00。

    请注意,所有T、Z和UTC都是不区分大小写解析的。

    典型的strftime实现对于此说明符有不同的(且依赖于区域的)格式。虽然Chrono的%+格式要稳定得多,但如果您想控制确切的输出,最好避免使用此说明符。

  • %s: 这不填充,并且可以为负数。对于Chrono的目的,它只考虑非闰秒,因此与ISO C strftime行为略有不同。

开始使用 Databend Cloud
低成本
快速分析
多种数据源
弹性扩展
注册