如何在没有误解的情况下将日期存储在 Spark 数据集中

How to store a Date in a Spark Dataset without misinterpretation

Java 8 java.time.LocalDate 允许您根据 YearMonthDayOfMonth 定义 Dates 而无需时区。它通过不具有 Long 底层表示,而是 YearMonthDayOfMonth 来实现这一点。这符合逻辑,因为在存储 Date 时,您不希望查看者根据时区将其解释为不同的日期。

java.sql.Date 然而是 "thin wrapper" 在 Long 表示上,这是 spark 中唯一支持的日期类型

因此,我的问题是,当您将 Date 存储在 Spark 数据集中并将其序列化到磁盘(即)parquet 文件时,如何确保它被读取并解释为正确的日期而不通过时区信息?

示例:

我可以在英格兰 (GMT+0) 解析字符串 "2016-01-01 02:00"。我真正想要存储的只是一个 day/month/year。但由于它是 java.sql.Date,所以它在凌晨 2 点存储底层的 unixtime。然后我将其连载,美国东海岸的某个人将其捡起并大放异彩。现在是 "2016-12-31 21:00"。但是,如果我知道时区,我就会知道它实际上是 "2016-01-01 02:00"。 如果 java.sql.Date 没有时区并且只使用 UTC 我能理解,但它使用 LocalTimeZone 来解释。

因此,由于 java.sql.Date 存储 unix,然后使用 LocalTimeZone 来解释 Date,我该如何存储不会被误解的 DateTime

java.sql.Date 不包含时区信息,您可以从 documentation.

中的主构造函数签名中看到

当时间戳存储在没有时区信息的地方时,您需要以某种方式带外传递此信息。最安全的选择是将其存储为 UTC 时间,因为 Unix 纪元是一个长期存在的约定,可以很容易地就与许多系统的兼容性达成一致。

由于 Spark 已经公开了处理 java.sql.Dates 和 java.sql.Timestamps 的工具,我建议您坚持使用这些工具(同时利用 org.spark.sql.functions 中的预定义函数)。

不幸的是,没有办法防止被误导的客户用错误的解释反序列化值。您可以将时区信息作为第二列的一部分传递,但是没有什么可以阻止用户仅获取存储在第一列中的值并假定它是本地日期(无论 "local" 在运行时上下文中意味着什么)。