UTC 或时区时间戳的 SQL 标准

cil*_*lap 2 java sql datetime timestamp date

我正在寻找一种标准的 SQL 方式,以确保独立于数据库具有带有 UTC 时间戳的列或带有时区信息的时间戳。在 DB 列中存储时间戳 UTC 的 UTC 示例:

  • 存储的 UTC 值 = 2014-01-01 15:30:00.000

    印度当地时间 21:00/9pm 作为本地时间戳“2014-01-01 21:00:00.000”

  • 存储的 UTC 值 = 2013-12-31 23:30:00.000

    印度当地时间 05:00/5am 作为本地时间戳“2014-01-01 05:00:00.000”

以 UTC 方式应用程序必须处理时区

现在我真的不知道如果可能的话,时间戳和时区与上述值

  • 存储的本地值 = 2014-01-01 21:00:00.000

    印度当地时间 21:00/9pm 作为本地时间戳“2014-01-01 21:00:00.000”

    但是有时区信息吗?

    或者如何获取这个时间戳的时区信息?

  • 存储的本地值 = 2014-01-01 05:00:00.000

    印度当地时间 05:00/5am 作为本地时间戳“2014-01-01 05:00:00.000”

    但是有时区信息吗?

    或者如何获取这个时间戳的时区信息?

希望有人能帮我走出黑暗?是否有关于时区问题和存储国际应用数据的良好做法?

Bas*_*que 6

tl;博士

要存储时间轴上的某个时刻,请定义 SQL 标准类型的数据库列TIMESTAMP WITH TIME ZONE

以 UTC 格式存储片刻。

Instant instant = Instant.now() ;  // Capture the current moment in UTC. 
myPreparedStatement.setObject( … , instant ) ;
Run Code Online (Sandbox Code Playgroud)

在 UTC 中检索片刻。

Instant instant = myResultSet.getObject( … , Instant.class ) ; 
Run Code Online (Sandbox Code Playgroud)

从 UTC 调整到时区。同一时刻,不同的挂钟时间。

ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;  // Specify time zone in proper `Continent/Region` name, never the ambiguous non-standard 3-4 letter pseudo-zone such as `IST` or `PST`. 
ZonedDateTime zdt = instant.atZone( z ) ;
Run Code Online (Sandbox Code Playgroud)

从时区调整为 UTC。同一时刻,不同的挂钟时间。

Instant instant = zdt.toInstant() ;
Run Code Online (Sandbox Code Playgroud)

日期时间不是字符串

严重的数据库不会将日期时间值存储为字符串。不要将数据库或 Java 库生成的字符串表示与日期时间值本身混淆。

存储UTC

最佳实践是将UTC用于您的数据库和其他存储,以及您的大部分业务逻辑。仅按用户预期出现在本地时区

有关标准日期时间类型,请参阅维基百科。即使您不使用 Postgres,也请查阅有关日期时间数据类型的优秀文档。但我确实推荐 Postgres,原因有很多,包括它对日期时间的出色支持。

TIMESTAMPZ

这位 Postgres 专家提出了简单而明智的建议:始终使用 TIMESTAMP WITH TIME ZONE

该数据类型的名称用词不当,造成了如此多的混乱。存储时区信息。这意味着尊重传入数据指示的时区,并且存储的值将调整为UTC。想想TIMESTAMP WITH TIME ZONE作为TIMESTAMP WITH RESPECT FOR TIME ZONE。大声重读这一段三遍,然后阅读上面的链接,并做一些实验以确保你理解。

您可能还想单独存储原始时区信息。不用于您的业务逻辑,而是用作调试的日志信息。

爪哇

对于 Java,请务必避免使用 java.util.Date 和 .Calendar 类。他们是出了名的麻烦。它们在Java 8 中被新的java.time 包所取代。使用该包和/或启发 java.time的Joda-Time 2.4 库。

时区

在 Java 中总是指定所需的时区。如果省略,您将隐式使用 JVM 的当前默认时区。这种隐含的默认值意味着您的结果会因时间和空间而异。这是日期时间工作中许多麻烦的根本原因。如果您想要 UTC,请使用 Joda-Time 中的常量,DateTimeZone.UTC.

忽略时区不会让您的生活更轻松。

ISO 8601

这个标准非常有用和明智。研究优秀的维基百科页面。应该是字符串表示的首选。

搜索 StackOverflow

这些问题已经涵盖在数百个甚至数千个答案中。