关于ClickHouse的配置文件config.xml中timezone、操作系统的时区
在ClickHouse的配置文件config.xml中,timezone配置项的主要作用是设置数据库服务器的默认时区。这个配置项会影响时间相关的数据类型和函数的行为。
如果config.xml中的timezone被注释
那么clickhouse取的是操作系统的时区,即TZ环境变量。
假如操作系统是TZ="UTC",那么clickhouse的timezone也是UTC
假如操作系统是TZ="Asia/Shanghai",那么clickhouse的timezone也是Asia/Shanghai
通过 SELECT timezone()可以查询当前应用的时区
如果在 config.xml 中配置了 timezone
那么 ClickHouse 的时区配置将与操作系统的时区无关。ClickHouse 会使用 config.xml 中指定的时区来解析和显示时间数据,而不会依赖或受限于操作系统的时区设置。
服务器1
config.xml 配置的是UTC
select now() 返回的是比北京时间小8小时;
服务器2
config.xml 配置的是 Asia/Shanghai
select now() 返回的是北京时间;
dbeaver使用use_server_time_zone,取的就是服务端的时区
关于clickhouse中的时间存储格式
以UTC(协调世界时)存储
DateTime类型的数据在ClickHouse中总是以UTC(协调世界时)存储。无论配置文件中的时区设置是什么,数据在磁盘上的实际存储形式不会受到影响。
无论clickhouse服务端config.xml文件配置的是什么时区,也无论服务端的操作系统配置的是什么时区(上面说了只有config没有配置timezone,才会从操作系统继承时区配置即环境变量TZ)。插入DateTime类型的数据时:
1、如果数据中包含时区信息,那么clickhouse就会根据数据中包含时区信息,转为UTC时区后,然后转为unix 时间戳进行存储。
2、如果插入的数据不包含时区信息
- 如果客户端指定的时区(设置了--use_client_time_zone true),那么clickhouse就按照客户端的来。
- 如果客户端没有指定,ClickHouse会使用config.xml中配置的默认时区来解析该时间。
- 然后,同样会将解析后的时间转换为UTC时间,并存储为Unix时间戳。
带时区例子
INSERT INTO test_table (event_time) VALUES ('2024-05-23 12:00:00+02:00');
不带时区例子
INSERT INTO test_table (event_time) VALUES ('2024-05-23 12:00:00');
例如:"2024-05-17 08:40:00"也是不带时区
数据中只有日期和时间部分 ("2024-05-17 08:40:00"),没有包含时区偏移量(如 +02:00)或时区标识(如 UTC)
关于clickhouse-client导入导出的时区问题
因为clickhouse-client导出的csv格式的数据,不包含时区信息,因此:
导出时候
如果不指定--session_timezone,那么clickhouse就使用config配置的(比如是UTC形式)。
再另一台机器导入的时候
如果当前客户端的TZ设置的是UTC,并且指定--use_client_time_zone 参数,那么clickhouse就按照UTC方式处理,那么没有问题。
如果不指定--use_client_time_zone,但此时config配置的是Asia/Shanghai,那么导入的数据就按照Asia/Shanghai处理了,那么数据整体就少了8小时。
检查数据
在clickhouse服务器上,使用不同的客时区查询数据,看数据是否正确。
正确的应该是UTC比Asia/Shanghai小于8小时;且最新的时间符合当前时间。
clickhouse-client --host 主机ip --port 端口 --user 用户名 --password '密码' --database db_name --session_timezone 'UTC' --query "select createTime from table order by createTime desc limit 1"
clickhouse-client --host 主机ip --port 端口 --user 用户名 --password '密码' --database db_name --session_timezone 'Asia/Shanghai' --query "select createTime from table order by createTime desc limit 1"
总结
关键是导出时候使用的时区,和导入时候使用的时区,二者相同即可。因为clickhouse最终是忽略时区,按照Unix时间戳存储的。但是clickhouse存储前,需要先根据当前的时区转为UTC时区,再把UTC格式的时间对象转为Unix时间戳。