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 时间戳存储在表中,时区用于在数据导入/导出期间将其转换为文本格式或反过来,或者在值上进行日历计算(例如:toDate
、toHour
函数等)。时区未存储在表的行中(或结果集中),而是存储在列元数据中。
可以在 IANA 时区数据库 中找到支持的时区列表,也可以通过 SELECT * FROM system.time_zones
查询。 列表 也在维基百科上提供。
在创建表时,您可以为 DateTime
类型列显式设置时区。例如:DateTime('UTC')
。如果未设置时区,ClickHouse 将在 ClickHouse 服务器启动时使用服务器设置或操作系统设置中的 timezone 参数的值。
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 │
└─────────────────────┴──────────┘
- 将日期时间作为整数插入时,它将被视为 Unix 时间戳 (UTC)。
1546300800
代表'2019-01-01 00:00:00'
UTC。但是,由于timestamp
列指定了Asia/Istanbul
(UTC+3) 时区,因此在作为字符串输出时,该值将显示为'2019-01-01 03:00:00'
。 - 将字符串值作为日期时间插入时,它将被视为处于列时区。
'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 分钟的倍数的时间点执行,您也可能会在这一特定日期获得不正确的结果。
非单调日历日期。例如,在 Happy Valley-Goose Bay,时间在 2010 年 11 月 7 日 00:01:00(午夜后一分钟)向后转换了一个小时。因此,在 11 月 6 日结束后,人们观察到 11 月 7 日的整整一分钟,然后时间又变回 11 月 6 日 23:01,并在另外 59 分钟后 11 月 7 日才开始。ClickHouse 尚未支持此类操作。在这些日期中,时间处理函数的结果可能略有不准确。
Casey 南极站 2010 年也存在类似问题。他们在 3 月 5 日 02:00 将时间倒退了三个小时。如果您在南极站工作,请不要害怕使用 ClickHouse。只需确保将时区设置为 UTC 或注意不准确之处。
跨越多个日期的时间偏移。一些太平洋岛屿将它们的时区偏移量从 UTC+14 更改为 UTC-12。这很好,但如果您对它们在转换日期的历史时间点进行计算,则可能会出现一些不准确之处。