PySpark设置spark.sql.session.timeZone为UTC后df.rdd.collect()转IST时区问题
PySpark读取MySQL timestamp时区转换问题解答
核心原因
spark.sql.session.timeZone和Python运行环境的时区是两个完全独立的配置,作用范围完全不同:
spark.sql.session.timeZone仅作用于Spark SQL的全链路逻辑:包括读取数据源时的时区解析、Spark SQL内置时间函数计算、df.show()输出时间的渲染逻辑,这也是你配置该参数后df.show()能正常输出UTC时间的原因。- 当你调用
df.rdd.collect()时,Spark会将内部存储的timestamp本质(UTC时间戳,即1970-01-01 00:00:00 UTC起的毫秒数)转换为Python原生的datetime对象。默认生成的是不带时区信息的naive datetime对象,Python在打印这类对象时,会自动读取当前运行环境的系统时区(你配置的IST)来渲染时间字符串,该过程完全不受Spark SQL时区配置的影响,所以就出现了自动转IST的问题。
解决方案
你可以根据自己的使用场景选择任意一种方案:
方案1:Spark层提前转字符串
在Spark侧就将timestamp字段按UTC格式转为字符串,再拉取到本地,完全规避Python时区转换的影响:
from pyspark.sql.functions import date_format, col df = df.withColumn("Mindate_str", date_format(col("Mindate"), "yyyy-MM-dd HH:mm:ss")) # 后续直接取Mindate_str字段即可 for row in df.collect(): print("row.Mindate ", row.Mindate_str)
方案2:修改Python运行环境时区
在代码最开头手动修改Python的运行时区为UTC,后续打印naive datetime时就会用UTC渲染:
import os import time os.environ['TZ'] = 'UTC' time.tzset() # 后续原有打印逻辑不变 for row in df.rdd.collect(): print("row.Mindate ",row.Mindate)
方案3:给datetime对象手动绑定UTC时区
对collect到的datetime对象手动添加UTC时区信息,打印时会显示正确的UTC时间:
import pytz utc_tz = pytz.UTC for row in df.rdd.collect(): utc_time = row.Mindate.replace(tzinfo=utc_tz) print("row.Mindate ", utc_time)
内容的提问来源于stack exchange,提问作者Arvind
相关产品推荐
相关产品推荐

