跳至主要内容

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 将在 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。这很好,但如果您对它们在转换日期的历史时间点进行计算,则可能会出现一些不准确之处。

另请参阅