Spark 结构流式处理自动将时间戳转换为本地时间

我的时间戳采用UTC和ISO8601,但使用结构化流,它会自动转换为本地时间。有没有办法阻止这种转换?我想用 UTC 格式使用它。

我正在从Kafka读取json数据,然后使用Spark函数解析它们。from_json

输入:

{"Timestamp":"2015-01-01T00:00:06.222Z"}

流:

SparkSession
  .builder()
  .master("local[*]")
  .appName("my-app")
  .getOrCreate()
  .readStream()
  .format("kafka")
  ... //some magic
  .writeStream()
  .format("console")
  .start()
  .awaitTermination();

图式:

StructType schema = DataTypes.createStructType(new StructField[] {
        DataTypes.createStructField("Timestamp", DataTypes.TimestampType, true),});

输出:

+--------------------+
|           Timestamp|
+--------------------+
|2015-01-01 01:00:...|
|2015-01-01 01:00:...|
+--------------------+

如您所见,小时本身已经增加。

PS:我试图尝试使用Spark函数,但没有运气。from_utc_timestamp


答案 1

对我来说,它的工作原理是使用:

spark.conf.set("spark.sql.session.timeZone", "UTC")

它告诉 spark SQL 使用 UTC 作为时间戳的默认时区。例如,我在spark SQL中使用它:

select *, cast('2017-01-01 10:10:10' as timestamp) from someTable

我知道它在2.0.1中不起作用。但可以在Spark 2.2中工作。我也用过,它的工作原理。SQLTransformer

我不确定流媒体。


答案 2

注意

这个答案主要在 Spark < 2.2 中有用。对于较新的Spark版本,请参阅astro-asz的答案

但是,我们应该注意,从Spark 2.4.0开始,没有设置()。因此,仅设置就可能导致 SQL 和非 SQL 组件使用不同时区设置的相当尴尬的情况。spark.sql.session.timeZoneuser.timezonejava.util.TimeZone.getDefaultspark.sql.session.timeZone

因此,我仍然建议显式设置,即使已设置。user.timezonespark.sql.session.timeZone

TL;DR不幸的是,这就是Spark现在处理时间戳的方式,除了直接在纪元时间上运行而不使用日期/时间实用程序之外,实际上没有内置的替代方案。

您可以在 Spark 开发人员列表中进行富有洞察力的讨论:SQL TIMESTAMP 语义与 SPARK-18350

到目前为止,我发现的最干净的解决方法是为驱动程序和执行程序设置为。例如,使用提交:-Duser.timezoneUTC

bin/spark-shell --conf "spark.driver.extraJavaOptions=-Duser.timezone=UTC" \
                --conf "spark.executor.extraJavaOptions=-Duser.timezone=UTC"

或通过调整配置文件 ():spark-defaults.conf

spark.driver.extraJavaOptions      -Duser.timezone=UTC
spark.executor.extraJavaOptions    -Duser.timezone=UTC

推荐