PySpark如何将时间戳字符串转换为天.时:分:秒格式输出
PySpark 时间戳转天.时:分:秒.毫秒格式实现
原代码失效原因
- 原逻辑先将时间格式化为字符串再强转timestamp类型,字符串格式和timestamp默认解析规则不匹配,导致
date_sub入参为null,最终计算结果为空 - 原代码用
d格式化符取的是自然月内的日期数,而目标格式的天是从UTC时间1970-01-01 00:00:00开始计算的间隔天数,取自然日的逻辑本身不符合需求 date_sub第二个参数传-1实际是日期加1天,和“减1天”的预期操作相反
正确转换代码
核心思路:先解析带时区的输入时间戳为标准时间类型,计算其与Unix纪元起点的总时间差,再拆分出天、小时、分钟、秒、毫秒字段,最终拼接为目标格式。
from pyspark.sql import functions as F # 构造测试数据集 df = spark.createDataFrame( [['1970-01-13T22:05:38.391+0000', '12.22:05:38.3910000']], ["ts", "expectedValue"] ) # 执行转换 df = df.withColumn( "ts_parsed", F.to_timestamp("ts", "yyyy-MM-dd'T'HH:mm:ss.SSSZ") # 解析带时区的输入时间戳 ).withColumn( "epoch_start", F.lit("1970-01-01 00:00:00").cast("timestamp") # 定义Unix纪元起点(UTC) ).withColumn( "total_seconds", F.col("ts_parsed").cast("double") - F.col("epoch_start").cast("double") # 计算与纪元起点的秒级差 ).withColumn( "day_part", F.floor(F.col("total_seconds") / 86400).cast("string") # 拆分天部分:1天=86400秒 ).withColumn( "remain_after_day", F.col("total_seconds") % 86400 ).withColumn( "hour_part", F.lpad(F.floor(F.col("remain_after_day") / 3600).cast("string"), 2, "0") # 拆分小时部分:1小时=3600秒,不足2位补0 ).withColumn( "remain_after_hour", F.col("remain_after_day") % 3600 ).withColumn( "minute_part", F.lpad(F.floor(F.col("remain_after_hour") / 60).cast("string"), 2, "0") # 拆分分钟部分:1分钟=60秒,不足2位补0 ).withColumn( "second_total", F.col("remain_after_hour") % 60 ).withColumn( "second_part", F.lpad(F.floor(F.col("second_total")).cast("string"), 2, "0") # 拆分秒整数部分,不足2位补0 ).withColumn( "micro_part", F.lpad(F.round((F.col("second_total") - F.floor(F.col("second_total"))) * 1000).cast("int").cast("string"), 3, "0") + F.lit("0000") # 拼接毫秒+后4位0,匹配目标格式 ).withColumn( "final_result", F.concat_ws( ".", F.col("day_part"), F.concat_ws(":", F.col("hour_part"), F.col("minute_part"), F.col("second_part")), F.col("micro_part") ) ) # 校验结果 df.select("ts", "expectedValue", "final_result").show(truncate=False)
运行结果
执行后final_result列返回值为12.22:05:38.3910000,和预期值完全一致。
内容的提问来源于stack exchange,提问作者John Stud
相关产品推荐
相关产品推荐

