PySpark struct嵌套时间字段合并为datetime类型及报错处理
问题原因说明
- explode报错原因:
explode()仅用于展开数组(Array)或映射(Map)类型的字段,你要处理的START_Time、REGISTRED都是Struct结构体类型,类型不匹配所以报错,该场景下无需使用explode,直接用字段名.子字段名即可访问结构体内部属性。 - 拼接出现
-----无效值原因:直接拼接时没有做非空判断,当结构体内部的时间字段全部为空时,拼接结果只剩下你手动加的分隔符-,就会出现全横线的无效值。
正确实现方案
核心逻辑是:先判断结构体或核心时间字段是否为空,为空则直接返回null;非空时先拼接为标准时间格式转为Timestamp类型,再按需求格式化为指定样式,同时用lpad补全单数字的月/日/时/分/秒,保证格式统一。
步骤1:导入依赖
from pyspark.sql import functions as F from pyspark.sql.types import TimestampType
步骤2:批量转换时间字段
因为两个时间字段的结构体结构完全一致,可以批量处理避免重复代码:
# 定义需要转换的时间字段列表 time_columns = ["START_Time", "REGISTRED"] for col_name in time_columns: df = df.withColumn( col_name, # 结构体为空或核心字段(年/月/日)为空时直接返回null F.when( (F.col(col_name).isNull()) | (F.col(f"{col_name}.year").isNull()) | (F.col(f"{col_name}.month").isNull()) | (F.col(f"{col_name}.day").isNull()), F.lit(None) ).otherwise( # 先拼接为标准时间格式转Timestamp类型 F.to_timestamp( F.concat( F.col(f"{col_name}.year"), F.lit("-"), F.lpad(F.col(f"{col_name}.month"), 2, "0"), F.lit("-"), F.lpad(F.col(f"{col_name}.day"), 2, "0"), F.lit(" "), F.lpad(F.col(f"{col_name}.hour"), 2, "0"), F.lit(":"), F.lpad(F.col(f"{col_name}.minute"), 2, "0"), F.lit(":"), F.lpad(F.col(f"{col_name}.second"), 2, "0") ), "yyyy-MM-dd HH:mm:ss" ) ) ) # 如果你需要输出为`yy-MM-dd-HH-mm-ss`格式的字符串而非Timestamp类型,取消注释下方代码 # df = df.withColumn(col_name, F.date_format(F.col(col_name), "yy-MM-dd-HH-mm-ss"))
注意事项
如果你的year字段存储的是两位年份(比如23代表2023),将to_timestamp中的格式字符串yyyy-MM-dd HH:mm:ss改为yy-MM-dd HH:mm:ss即可。
内容的提问来源于stack exchange,提问作者Anis
相关产品推荐
相关产品推荐

