跳到主要内容
跳到主要内容

DateTime

允许存储时间瞬间,可以表示为日历日期和一天中的时间。

语法

DateTime([timezone])

支持的值范围:[1970-01-01 00:00:00, 2106-02-07 06:28:15]。

分辨率:1 秒。

速度

大多数情况下,Date 数据类型比 DateTime 更快。

Date 类型需要 2 个字节的存储空间,而 DateTime 需要 4 个字节。但是,当数据库压缩时,这种差异会被放大。这种放大的原因是 DateTime 中的分钟和秒不太容易压缩。过滤和聚合 Date 而不是 DateTime 也更快。

使用说明

时间点以 Unix 时间戳 形式保存,与时区或夏令时无关。时区影响 DateTime 类型值以文本格式显示的方式,以及指定为字符串的值的解析方式(‘2020-01-01 05:00:01’)。

时区无关的 Unix 时间戳存储在表中,时区用于在数据导入/导出期间或对值进行日历计算(例如:toDatetoHour 函数等)时将其转换为文本格式或转换回。时区不存储在表的行中(或结果集中),而是存储在列元数据中。

支持的时区列表可以在 IANA 时区数据库 中找到,也可以通过 SELECT * FROM system.time_zones 查询。列表 也可在维基百科上找到。

您可以在创建表时为 DateTime 类型列显式设置时区。示例:DateTime('UTC')。如果未设置时区,ClickHouse 将使用服务器设置中 timezone 参数的值,或 ClickHouse 服务器启动时操作系统设置的值。

clickhouse-client 在初始化数据类型时如果未显式设置时区,则默认应用服务器时区。要使用客户端时区,请使用 --use_client_time_zone 参数运行 clickhouse-client

ClickHouse 根据 date_time_output_format 设置的值输出值。默认情况下为 YYYY-MM-DD hh:mm:ss 文本格式。此外,您可以使用 formatDateTime 函数更改输出。

将数据插入 ClickHouse 时,您可以根据 date_time_input_format 设置的值使用不同的日期和时间字符串格式。

示例

1. 创建具有 DateTime 类型列的表并将数据插入其中

CREATE TABLE dt
(
`timestamp` DateTime('Asia/Istanbul'),
`event_id` UInt8
)
ENGINE = TinyLog;
-- Parse DateTime
-- - from string,
-- - from integer interpreted as number of seconds since 1970-01-01.
INSERT INTO dt VALUES ('2019-01-01 00:00:00', 1), (1546300800, 3);

SELECT * FROM dt;
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │ 2 │
│ 2019-01-01 03:00:00 │ 1 │
└─────────────────────┴──────────┘
  • 当将 datetime 作为整数插入时,它被视为 Unix 时间戳 (UTC)。1546300800 表示 '2019-01-01 00:00:00' UTC。但是,由于 timestamp 列指定了 Asia/Istanbul (UTC+3) 时区,因此当作为字符串输出时,该值将显示为 '2019-01-01 03:00:00'
  • 当将字符串值作为 datetime 插入时,它被视为位于列时区中。'2019-01-01 00:00:00' 将被视为位于 Asia/Istanbul 时区,并保存为 1546290000

2. 过滤 DateTime

SELECT * FROM dt WHERE timestamp = toDateTime('2019-01-01 00:00:00', 'Asia/Istanbul')
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │ 1 │
└─────────────────────┴──────────┘

可以使用 WHERE 谓词中的字符串值过滤 DateTime 列值。它将自动转换为 DateTime

SELECT * FROM dt WHERE timestamp = '2019-01-01 00:00:00'
┌───────────timestamp─┬─event_id─┐
│ 2019-01-01 00:00:00 │ 1 │
└─────────────────────┴──────────┘

3. 获取 DateTime 类型列的时区

SELECT toDateTime(now(), 'Asia/Istanbul') AS column, toTypeName(column) AS x
┌──────────────column─┬─x─────────────────────────┐
│ 2019-10-16 04:12:04 │ DateTime('Asia/Istanbul') │
└─────────────────────┴───────────────────────────┘

4. 时区转换

SELECT
toDateTime(timestamp, 'Europe/London') as lon_time,
toDateTime(timestamp, 'Asia/Istanbul') as mos_time
FROM dt
┌───────────lon_time──┬────────────mos_time─┐
│ 2019-01-01 00:00:00 │ 2019-01-01 03:00:00 │
│ 2018-12-31 21:00:00 │ 2019-01-01 00:00:00 │
└─────────────────────┴─────────────────────┘

由于时区转换仅更改元数据,因此该操作没有计算成本。

时区支持的限制

某些时区可能无法完全支持。存在以下几种情况

如果与 UTC 的偏移量不是 15 分钟的倍数,则小时和分钟的计算可能不正确。例如,利比里亚蒙罗维亚的时区在 1972 年 1 月 7 日之前偏移 UTC -0:44:30。如果您对蒙罗维亚时区的历史时间进行计算,则时间处理函数可能会给出不正确的结果。1972 年 1 月 7 日之后的结果仍然是正确的。

如果时间转换(由于夏令时或其他原因)在不是 15 分钟倍数的时间点执行,那么在这一天您也可能会得到不正确的结果。

非单调日历日期。例如,在加拿大鹅湾欢乐谷,时间在 2010 年 11 月 7 日 00:01:00(午夜后一分钟)向后调整了一小时。因此,在 11 月 6 日结束后,人们观察了整整一分钟的 11 月 7 日,然后时间改回 11 月 6 日 23:01,再过 59 分钟,11 月 7 日再次开始。ClickHouse 尚不支持这种乐趣。在这些日子里,时间处理函数的结果可能略有不正确。

2010 年南极洲凯西站也存在类似问题。他们在 3 月 5 日 02:00 将时间向后调整了三个小时。如果您在南极站工作,请不要害怕使用 ClickHouse。只需确保将时区设置为 UTC 或注意不准确之处即可。

多天的时移。一些太平洋岛屿将其时区偏移从 UTC+14 更改为 UTC-12。这没问题,但如果您在转换日对其历史时间点使用其时区进行计算,则可能会出现一些不准确之处。

参见