JDBC 读/写中的 Spark 时间戳时区

dev*_*v ツ 4 amazon-web-services apache-spark

我正在通过从 Oracle 读取数据来创建镶木地板文件。

Oracle 以 UTC 运行。我确认使用,

SELECT DBTIMEZONE FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

输出:

DBTIMEZONE|
----------|
+00:00    |
Run Code Online (Sandbox Code Playgroud)

从 JDBC 读取并以 parquet 形式写入 S3:

df = spark.read.format('jdbc').options(url=url,
                                           dbtable=query,
                                           user=user,
                                           password=password,
                                           fetchsize=2000).load()

df.write.parquet(s3_loc, mode="overwrite")
Run Code Online (Sandbox Code Playgroud)

现在,我检查了spark.sql.session.timeZone

print(spark.conf.get("spark.sql.session.timeZone"))
Run Code Online (Sandbox Code Playgroud)

输出:

UTC
Run Code Online (Sandbox Code Playgroud)

现在,我正在从 S3 位置读取数据:

df1 = spark.read.parquet(s3_loc)
df1.show()
Run Code Online (Sandbox Code Playgroud)

输出:

+-------------------+
|             col1  |
+-------------------+
|2012-11-11 05:00:00|
|2013-11-25 05:00:00|
|2013-11-11 05:00:00|
|2014-12-25 05:00:00|
+-------------------+
Run Code Online (Sandbox Code Playgroud)

col1是oracle中的日期并转换为spark df中的时间戳。

为什么输出中要添加 5 小时?数据库以 UTC 运行,并且spark.sql.session.timeZone是 UTC。

笔记:

  1. RDS 和 EMR 均在 AWS US-EAST-1 中运行
  2. 在所有 Spark 节点上,我运行了TZ=UTC

Kom*_*owy 5

时区由 JDBC 驱动程序识别,它不知道 Spark 的时区设置,而是依赖于 JVM 的默认时区。此外,它忽略远程数据库会话的时区设置。你说你跑了TZ=UTC——我不确定,但可能没用。检查TimeZone.getDefault告诉你什么。

正如我怀疑的那样,如果您的 JVM 时区是 EDT(US-EAST-1 是弗吉尼亚州),那么2012-11-11 00:00:00通过 JDBC 从 Oracle 读取的数据将被解释为 EDT。Spark 中显示的是2012-11-11 05:00:00UTC,这就是您得到的结果。

要修复此问题,请在运行 Spark-submit 时覆盖 JVM 默认时区:

spark-submit \
--conf "spark.driver.extraJavaOptions=-Duser.timezone=UTC" \
--conf "spark.executor.extraJavaOptions=-Duser.timezone=UTC" \
...
Run Code Online (Sandbox Code Playgroud)