背景
使用以下两个包进行 clickhouse 查询数据缓存,发现命中缓存时,返回的时间类型字段的值偏移了八个小时,服务器时区是零时区
问题原因
直接通过数据库查询的时间是东八区,比如 2024-12-05 00:00:05.657 +0800 CST
,
但是后面命中缓存从中拿到的时区是零时区(服务器时区是零时区),比如 2024-12-04 16:00:05.657 +0000 UTC
,
这样再对时间字段做格式化的时候就会差了八个时区,
不过这时候缓存已丢失了最开始查询所携带的时区
解决方法
- 缓存查询数据的同时,缓存列的信息,来自 sql.DatabaseTypeName(),比如 DateTime64(3, 'Asia/Shanghai')
- 查询命中缓存时通过解析列信息列得到时区
- 对时间字段指定解析后的时区进行格式化
不过本质原因是缓存包使用 msgpack
进行序列化,该方式没有保存时区信息,
因此还可以有其他的解决方法,
- 寻找
msgpack
关于时间类型的扩展 - 实现新的缓存包的接口,使用其他序列化方式,比如
json
发现一个有意思的现象,通过 union
的方式查询两条不同时区的数据,后续的数据都会转换成第一条数据所拥有的时区。