PySpark to_timestamp解析可变长度毫秒如何正确归一化为SSS格式
问题根因
Spark 3.2.1 内置to_timestamp使用SimpleDateFormat做时间格式解析时,固定写死SSS匹配毫秒会按左对齐逻辑处理长度不足3位的毫秒值:直接读取小数点后连续的数字,不足3位时在左侧补0凑够3位,完全不符合毫秒作为时间小数位需要右侧补0的逻辑,因此出现解析错位。另外原格式串里小时位用hh是12小时制,遇到12点之后的时间会直接解析错误,需要替换为24小时制的HH。
解决方案
不要直接把原始字符串传入固定格式的to_timestamp,先做字符串预处理,把毫秒位统一右补0到3位,再做时间解析:
- 用正则拆分出时间字符串里「小数点前的前缀部分」「小数点后的毫秒数字部分」「末尾的Z时区标识」
- 对提取到的毫秒数字段用
rpad函数右侧补0,统一填充到3位长度 - 拼接成标准的3位毫秒UTC时间字符串,再传入
to_timestamp按固定格式解析
可直接复用的代码如下:
import pyspark.sql.functions as F test = spark.createDataFrame([ (1,'2022-06-16T07:01:25.346Z'), (2,'2022-06-16T06:54:21.51Z'), (3,'2022-06-16T06:54:21.5Z') ],['no','timing1']) # 预处理:统一补全毫秒到3位 test = test.withColumn( "time_prefix", F.regexp_extract(F.col("timing1"), r"^(.*\.)", 1) ).withColumn( "millisecond", F.rpad(F.regexp_extract(F.col("timing1"), r"\.(\d+)Z$", 1), 3, "0") ).withColumn( "standard_time_str", F.concat(F.col("time_prefix"), F.col("millisecond"), F.lit("Z")) ) # 按标准格式解析,注意小时用24小时制HH parse_format = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" test = test.withColumn("correct_time", F.to_timestamp(F.col("standard_time_str"), format=parse_format)) # 输出验证结果 test.select("timing1", "correct_time").show(truncate=False)
解析结果
运行后输出完全符合预期:
+------------------------+-----------------------+ |timing1 |correct_time | +------------------------+-----------------------+ |2022-06-16T07:01:25.346Z|2022-06-16 07:01:25.346| |2022-06-16T06:54:21.51Z |2022-06-16 06:54:21.51 | |2022-06-16T06:54:21.5Z |2022-06-16 06:54:21.5 | +------------------------+-----------------------+
内容的提问来源于stack exchange,提问作者lil-wolf
相关产品推荐
相关产品推荐

