哪种MySQL类型最能存储时间点信息 - 日期时间或时间戳

时间:2018-05-30 16:28:45

标签: java mysql datetime timestamp iso8601

简介

我之前已经意识到类似的问题。但我仍然需要对我的用例进行更多测试 - 我对结果感到有些惊讶/困惑。

以下是测试和结果的描述(带代码)。

我正在处理以下应用程序:

  • 记录事件历史记录(在某个时间点发生的事情)。
    • 这段历史是不可改变的。一旦事件被写入,我们就不会更改它。
    • 我们报告此历史。
  • 安排未来,可能是经常性的行动。例如,"每周五进行此检查。"

因此,清楚地了解时间数据非常重要。

我正在尝试了解MySQL中的时间戳类型(日期时间和时间戳)以及它们如何与Java代码和ISO8601时间串交互。

我已经围绕其Timestamp类型阅读了MySQL文档 - 它如何转换时间值以将其存储为UTC,并在检索时将该UTC值转换为服务器或会话时区。这听起来像是好的"时间点"存储。

日期时间MySQL类型更不透明。本文(http://code.openark.org/blog/mysql/timestamp-vs-datetime-which-should-i-be-using)认为它与字符串没那么不同。 我重复了#34; SELECT NOW()+ 0;"查询并获得与文章相同的答案。

为了澄清事情,我写了一个小的Java类,写入一个由3列组成的数据库表:

  • tz(表示标准时区ID的字符串)。 UTC用于测试 - 但它不是时区。
  • mydatetime(日期时间栏)
  • mytimestamp(时间戳列)

Java代码

Java代码位于:https://gist.github.com/iliomad/c6d8a50613fa99e2d079b8ad3b9eca4d

测试1

我创建了3个不同的ISO8601时间戳字符串 - 全部用于同一时间点 - 但具有不同的偏移/时区。 每个都写入数据库,检索并打印出来。

首先,我将MySQL数据库服务器时区设置为" +00:00"。

输出

将时间写入数据库。

UTC
2018-04-13T11:12:00Z, 1523617920
Europe/Amsterdam
2018-04-13T13:12:00+02:00, 1523617920
Asia/Calcutta
2018-04-13T16:42:00+05:30, 1523617920

从数据库中读取存储的时间。

Description, Datetime column (epoch seconds), Datetime column (as ISO string), Timestamp column (as epoch seconds), Timestamp column (as ISO string)
UTC, 1523617920, 2018-04-13T11:12:00Z, 1523617920, 2018-04-13T11:12:00Z
Europe/Amsterdam, 1523617920, 2018-04-13T13:12+02:00[Europe/Amsterdam],       1523617920, 2018-04-13T13:12+02:00[Europe/Amsterdam]
Asia/Calcutta, 1523617920, 2018-04-13T16:42+05:30[Asia/Calcutta], 1523617920, 2018-04-13T16:42+05:30[Asia/Calcutta]

一切看起来都不错。纪元秒数(如https://www.epochconverter.com/之类的内容)与ISO8601时间字符串一致。

测试2

然后我将MySQL服务器的时区从UTC(+00:00)更改为欧洲/阿姆斯特丹(+02:00)并再次读取存储的时间。

输出

从数据库中读取存储的时间。

Description, Datetime column (epoch seconds), Datetime column (as ISO string), Timestamp column (as epoch seconds), Timestamp column (as ISO string)
UTC, 1523617920, 2018-04-13T11:12:00Z, 1523625120, 2018-04-13T13:12:00Z
Europe/Amsterdam, 1523617920, 2018-04-13T13:12+02:00[Europe/Amsterdam], 1523625120, 2018-04-13T15:12+02:00[Europe/Amsterdam]
Asia/Calcutta, 1523617920, 2018-04-13T16:42+05:30[Asia/Calcutta], 1523625120, 2018-04-13T18:42+05:30[Asia/Calcutta]

我的期望是Datetime列会受到影响 - 认为它没有存储时区信息。但是,它移动了时间戳列。

结论

我们不会经常更改服务器时区。 我试图看看哪种MySQL数据类型最能代表某个时间点 - 我可以指望它是准确和不变的(而不是头部破坏)。在上述基础上,如果我以ISO8601字符串的形式提供时间点信息,则Datetime MySQL类型将保留所提供的信息。

我的测试代码不正确和/或我对结果的解释完全可能。 可以在这里做一点指导。

在上面的测试用例中,Datetime MySQL类型是否能更好地存储时间点信息?

1 个答案:

答案 0 :(得分:1)

经过一些调整后,我得到了一个Java类,可以设法存储和检索时间点信息。我对此仍然有些紧张 - 很多部分想要在时间上发表意见,这让我感到不舒服。

这个课在这里的原始要点:https://gist.github.com/iliomad/c6d8a50613fa99e2d079b8ad3b9eca4d(和修订显示更改)。

  • 我可以将MySQL服务器时区更改为我想要的任何内容。我还是把我放进去了。
    • 直接在MySQL查询管理器中的查询也表现为 - unix epoch保持稳定的时间戳列。这就是我的期望。
    • 从basic_time选择tz,mydatetime,unix_timestamp(mydatetime)为mydatetime_as_epoch,unix_timestamp(mytimestamp);
    • tz = timezone id(String); mydatetime(日期时间列); mytimestamp(时间戳列)
  • 时间戳MySQL类型是时间戳。我不需要弄乱它。

    • Java 8 java.sql.Timestamp类fromInstant和toInstant方法声称保持相同的时间点。
    • 我在setObject和getObject preparedStatement方法上尝试过Instant。 MySQL连接器/ J只是不接受它们 - 我深入研究了源代码。
  • 日期时间MySQL类型I仍然有点困惑(我不知道它是什么)但知道时区我可以保留时间点信息。

  • 我尝试了MySQL Connector / J 5.1.46和8.0.11版本。每个人的行为相同。
  • JDBC参数useLegacyDatetimeCode = false似乎很重要。我需要运行更多的测试,无论是否有此确认。

尚未完全分析这一点。试图解决这个问题并不好玩。