最近我们有个按照年龄分布的统计分析需求,数据分析师要分析大于50岁的人群有多少,他用了toDate处理字段birthday转换时间格式,通过dateDiff来对比生日时间和当前时间,从而计算年龄。然后这样的计算,我们计算出来的超过50的岁的数据占比很大,我们怎么想也觉得不太可能有这么多老年人玩我们的产品,如果是微信那样的产品,那还有可能。出于这样的怀疑,我们去细查我们当时写的sql:
datediff('year',toDate(birthday),toDate(now()))
我们查了一些明细,发现明明有60岁的,也有为空的数据,都变成了51岁。发现了这个规则之后我们把sql拆出来看看计算结果。比如:
datediff('year', toDate('1952-02-01'), toDate(now()))
这个返回是51,接下来拆分toDate('1952-02-01')的值,发现结果变成了1970-01-01,试了好几个值都变成1970-01-01。
经过验证,在官网的issue里面找到相关回答:We don't support dates before unix epoch.意思就是说unix时间戳之前的时间不支持。链接如下:https://github.com/ClickHouse/ClickHouse/issues/18511,所以针对于1970年之前的时间计算都会变成51岁,这样会造成统计的数据不准确。
发现这个问题之后,我们调整了实现方案,通过截取birthday字段的前四位转成int32,然后取当前的年去做相减,得到年龄,通过这样的方法之后才获取到正确的值。sql如下:
select minus(cast(toYear(now()),'Int32'),cast(substring('1952-02-01',1,4),'Int32'))
这样就正确解决了unix时间戳之前的时间不支持问题。