将 UTC unixtime 转换为同一时区的时间戳

问题描述

我想将 epoc 字段转换为 UTC 时间戳,我正在使用下面的代码

df.withColumn(
  TargetColumn,to_timestamp(from_unixtime(col(SourceColumn) / 1000),"yyyy-MM-dd HH:mm:ss")

SourceColumn 的示例值是 1580452395095L,它应该产生 2020-01-31 06:33:15.0 但是,当我尝试此代码时,它给出了 2020-01-31 07:33:15.0

好像 to_timestamp 函数使用的是系统的本地时区,我什至尝试将 spark 时区设置为

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

但这也不起作用,有没有办法让这段代码始终转换为 UTC 时间戳,而不管它在什么环境下运行?

解决方法

在配置中设置时区应该可以解决这个问题。实际上在配置中的任何地方设置 "spark.sql.session.timeZone","UTC" 应该可以工作。

val spark = SparkSession.builder()
    .appName("test")
    .master("local")
    .config("spark.sql.session.timeZone","UTC").getOrCreate()

import spark.implicits._

val df = Seq(
  (1580452395095L)
).toDF("DATE")

df.withColumn("NEW_DATE",to_timestamp(from_unixtime(col("DATE") / 1000),"yyyy-MM-dd HH:mm:ss"))
    .show(false)

输出:

+-------------+-------------------+
|DATE         |NEW_DATE           |
+-------------+-------------------+
|1580452395095|2020-01-31 06:33:15|
+-------------+-------------------+

不设置时区,我们得到

+-------------+-------------------+
|DATE         |NEW_DATE           |
+-------------+-------------------+
|1580452395095|2020-01-31 07:33:15|
+-------------+-------------------+
,

如果您只想为特定的数据帧操作启用它,而不管 spark 会话是如何创建的,那么这应该会有所帮助。

默认为

java.time.ZoneId.systemDefault

res50: java.time.ZoneId = Asia/Calcutta

当您查询 spark 配置时,同样会反映出来。

spark.sql("SET spark.sql.session.timeZone").show(false)

+--------------------------+-------------+
|key                       |value        |
+--------------------------+-------------+
|spark.sql.session.timeZone|Asia/Calcutta|
+--------------------------+-------------+

现在是数据框

val df = Seq((1580452395095L)).toDF("DATE")

将其更改为 UTC - 伦敦

spark.conf.set("spark.sql.session.timeZone","Europe/London")

查询配置设置将显示伦敦

spark.sql("SET spark.sql.session.timeZone").show(false)

+--------------------------+-------------+
|key                       |value        |
+--------------------------+-------------+
|spark.sql.session.timeZone|Europe/London|
+--------------------------+-------------+

结果:

df.withColumn("NEW_DATE",to_timestamp(from_unixtime(col("DATE") / 1000))).show(false)

+-------------+-------------------+
|DATE         |NEW_DATE           |
+-------------+-------------------+
|1580452395095|2020-01-31 06:33:15|
+-------------+-------------------+

改回系统默认,

spark.conf.set("spark.sql.session.timeZone",java.time.ZoneId.systemDefault.toString)

df.withColumn("NEW_DATE",to_timestamp(from_unixtime(col("DATE") / 1000))).show(false)

+-------------+-------------------+
|DATE         |NEW_DATE           |
+-------------+-------------------+
|1580452395095|2020-01-31 12:03:15|
+-------------+-------------------+

spark.sql("SET spark.sql.session.timeZone").show(false)

+--------------------------+-------------+
|key                       |value        |
+--------------------------+-------------+
|spark.sql.session.timeZone|Asia/Calcutta|
+--------------------------+-------------+
,

您可以尝试在 $SPARK_HOME/conf/spark-defaults.conf 文件中附加以下行:

spark.sql.session.timeZone UTC

如有必要,您还可以使用以下方法设置 JVM 时区:

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