背景

使用以下两个包进行 clickhouse 查询数据缓存,发现命中缓存时,返回的时间类型字段的值偏移了八个小时,服务器时区是零时区

问题原因

直接通过数据库查询的时间是东八区,比如 2024-12-05 00:00:05.657 +0800 CST
但是后面命中缓存从中拿到的时区是零时区(服务器时区是零时区),比如 2024-12-04 16:00:05.657 +0000 UTC
这样再对时间字段做格式化的时候就会差了八个时区,
不过这时候缓存已丢失了最开始查询所携带的时区

解决方法

  1. 缓存查询数据的同时,缓存列的信息,来自 sql.DatabaseTypeName(),比如 DateTime64(3, 'Asia/Shanghai')
  2. 查询命中缓存时通过解析列信息列得到时区
  3. 对时间字段指定解析后的时区进行格式化

不过本质原因是缓存包使用 msgpack 进行序列化,该方式没有保存时区信息,
因此还可以有其他的解决方法,

  1. 寻找msgpack 关于时间类型的扩展
  2. 实现新的缓存包的接口,使用其他序列化方式,比如 json

发现一个有意思的现象,通过 union 的方式查询两条不同时区的数据,后续的数据都会转换成第一条数据所拥有的时区。

企业微信截图_340b3956-8237-464e-8e13-e09e3077606c