首页 > 解决方案 > JDBC读/写中的火花时间戳时区

问题描述

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

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

SELECT DBTIMEZONE FROM DUAL;

输出:

DBTIMEZONE|
----------|
+00:00    |

从 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")

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

print(spark.conf.get("spark.sql.session.timeZone"))

输出:

UTC

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

df1 = spark.read.parquet(s3_loc)
df1.show()

输出:

+-------------------+
|             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|
+-------------------+

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

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

笔记:

  1. RDS 和 EMR 都在 AWS US-EAST-1 中运行
  2. 在所有的火花节点上,我跑了TZ=UTC

标签: amazon-web-servicesapache-spark

解决方案


时区由 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" \
...

推荐阅读