Spark SQL如何正确按日期范围过滤,解决结束日期丢失问题?
问题根因
你遇到的问题核心是Spark SQL隐式时区转换导致的日期比较偏差:
- 你的Spark会话时区和数据存储使用的时区不一致,你查询的
date字段隐式转换为TIMESTAMP时使用的是CEST时区(中欧夏令时,比UTC快2小时) - 当你直接用字符串
'2021-06-27'和date字段比较时,Spark会默认把字符串转换为对应UTC时区的TIMESTAMP:'2021-06-27 00:00:00 UTC'对应 CEST 时区的2021-06-27 02:00:00,而你存储的date字段转TIMESTAMP是2021-06-27 00:00:00 CEST,早于转换后的字符串时间,所以不会被包含在<= '2021-06-27'的结果里。
正确的日期比较方案
方案1:统一用to_date做显式日期转换(最稳妥)
直接对比较两边都做to_date转换,强制比较日期粒度的值,完全跳过时区影响,就是你测试有效的写法:
WHERE to_date(`date`) BETWEEN to_date('2021-06-14') AND to_date('2021-06-27')
注:如果输入字符串已经是yyyy-MM-dd标准格式,不需要额外指定格式参数,Spark可以自动识别
方案2:显式指定会话时区规避隐式转换
在执行查询前先设置会话时区和你数据存储的时区一致,后续直接比较就不会出现偏差:
-- 设置为你数据使用的时区,这里对应你示例的CEST时区 SET spark.sql.session.timeZone = 'Europe/Paris'; -- 后续直接比较即可正常命中27日的数据 SELECT `date` FROM dummytesttable WHERE `date` between '2021-06-14' and '2021-06-27' GROUP BY `date` ORDER BY `date`
方案3:显式转换字符串为对应时区的时间
如果不想修改全局会话时区,可以在比较时手动把字符串参数转换为对应时区的时间:
WHERE `date` BETWEEN to_timestamp('2021-06-14', 'yyyy-MM-dd', 'Europe/Paris') AND to_timestamp('2021-06-27 23:59:59', 'yyyy-MM-dd HH:mm:ss', 'Europe/Paris')
内容的提问来源于stack exchange,提问作者anstue
相关产品推荐
相关产品推荐

