PySpark写入Parquet时0001-01-01与9999-12-31日期输出异常问题
PySpark 3.0.1写入Parquet文件极端日期异常问题分析及解决方案
问题原因
该问题是Spark 3.0.x版本的已知bug,触发逻辑如下:
- Spark 3.0默认启用了新版datetime处理机制,向Parquet写入Timestamp类型数据时,默认采用
TIMESTAMP_MICROS(微秒精度)格式编码。该格式的有效取值范围为1677-09-21 00:12:43.145224192~2262-04-11 23:47:16.854775807,你使用的0001-01-01、9999-12-31均超出该范围,会触发Int64整数溢出,导致日期回绕为错误值。 - 写入CSV时Spark直接将日期时间格式化为字符串输出,不涉及Parquet的二进制编码规则,因此不会出现精度溢出问题。
修复方案
可以根据实际场景选择以下方案:
- 升级Spark版本:该bug在Spark 3.1.0及后续版本已官方修复,升级后写入超出范围的时间戳时会自动切换为
TIMESTAMP_MILLIS(毫秒精度)编码,不会触发溢出问题。 - 启用旧版兼容规则:如果暂时无法升级版本,可以在写入Parquet前添加以下配置,沿用Spark 2.x的时间编码逻辑:
spark.conf.set("spark.sql.legacy.parquet.datetimeRebaseModeInWrite", "LEGACY") spark.conf.set("spark.sql.parquet.outputTimestampType", "TIMESTAMP_MILLIS")
- 转换为Date类型存储:如果业务不需要时间精度,可以将Timestamp类型转换为Date类型后写入,Parquet的Date类型天然支持
0001-01-01~9999-12-31的取值范围,完全覆盖业务场景,转换示例如下:
from pyspark.sql.functions import to_date sparkDF = sparkDF.withColumn("目标日期字段名", to_date("目标日期字段名"))
- 新增字符串备份字段:极端场景下可以额外新增一个字符串类型字段,存储原始日期时间的格式化结果,作为校验兜底。
内容的提问来源于stack exchange,提问作者Marco Rosas
相关产品推荐
相关产品推荐

