PySpark to_timestamp解析差异:yyyy/MM/dd返回NULL,yyyy-MM-dd报错原因
PySpark日期解析行为差异问题解答
问题场景
在PySpark DataFrame中存在一个string类型的CallDate列,值格式为:
2008-04-01T00:00:00 2008-04-01T00:00:00
尝试使用pyspark.sql.functions.to_timestamp()转换时出现两种不同结果:
- 执行以下代码,
IncidentDate列全为NULL:
结果:df.withColumn('IncidentDate', to_timestamp(col('CallDate'), 'yyyy/MM/dd')).select('CallDate', 'IncidentDate').show()+-------------------+------------+ | CallDate|IncidentDate| +-------------------+------------+ |2008-04-01T00:00:00| NULL| |2008-04-01T00:00:00| NULL| +-------------------+------------+ - 执行以下代码,直接抛出错误:
错误信息:df.withColumn('IncidentDate', to_timestamp(col('CallDate'), 'yyyy-MM-dd')).select('CallDate', 'IncidentDate').show()Caused by: org.apache.spark.SparkUpgradeException: [INCONSISTENT_BEHAVIOR_CROSS_VERSION.PARSE_DATETIME_BY_NEW_PARSER] You may get a different result due to the upgrading to Spark >= 3.0: Fail to parse '2008-04-01T00:00:00' in the new parser. You can set "spark.sql.legacy.timeParserPolicy" to "LEGACY" to restore the behavior before Spark 3.0, or set to "CORRECTED" and treat it as an invalid datetime string.
原因分析
1. 使用yyyy/MM/dd返回NULL的原因
Spark日期解析器会严格匹配格式字符串与输入字符串的分隔符及整体结构:
- 格式
yyyy/MM/dd要求日期部分用斜杠/分隔,但输入字符串的日期部分用短横线-分隔,且后续带有T00:00:00的时间后缀,完全不符合指定格式。 - 这种情况下,解析器判定输入无法匹配格式,触发容错逻辑返回NULL,不会抛出错误(这是Spark默认的解析失败处理方式)。
2. 使用yyyy-MM-dd抛出错误的原因
- 输入字符串的前8位
2008-04-01与格式yyyy-MM-dd的结构匹配,但字符串末尾存在额外的T00:00:00内容。 - Spark 3.0+启用了新的日期解析器,默认要求输入字符串完全匹配格式字符串,不允许有未被格式覆盖的剩余字符。当解析到匹配的日期部分后发现还有剩余内容,解析器判定为无效的日期时间字符串,触发严格校验并抛出异常。
- 旧版Spark(3.0之前)的解析器会忽略格式匹配后的剩余内容,不会报错,因此错误提示中提到可以通过设置
spark.sql.legacy.timeParserPolicy参数切换到旧行为。
正确解析方式
使用完全匹配的格式字符串yyyy-MM-dd'T'HH:mm:ss,代码示例:
from pyspark.sql.functions import to_timestamp, col df.withColumn('IncidentDate', to_timestamp(col('CallDate'), 'yyyy-MM-dd\'T\'HH:mm:ss')) \ .select('CallDate', 'IncidentDate') \ .show()
由于输入字符串符合ISO 8601标准,也可以省略格式参数,Spark会自动识别:
df.withColumn('IncidentDate', to_timestamp(col('CallDate'))) \ .select('CallDate', 'IncidentDate') \ .show()
内容的提问来源于stack exchange,提问作者DumbCoder
相关产品推荐
相关产品推荐

