Java 哪种MySQL类型最适合存储时间点信息—日期时间还是时间戳 介绍

Java 哪种MySQL类型最适合存储时间点信息—日期时间还是时间戳 介绍,java,mysql,datetime,timestamp,iso8601,Java,Mysql,Datetime,Timestamp,Iso8601,我意识到以前这里也有人问过类似的问题。但是我仍然需要为我的用例做更多的测试——我对结果有点惊讶/困惑 以下是测试代码和结果的说明 我正在开发一个应用程序: 记录在某个时间点发生的事件历史记录。 这段历史是一成不变的。一旦事件被写入,我们不会更改它。 我们报道这段历史。 计划未来可能重复的行动。例如,每周五做这项检查。 因此,对时间数据的清晰理解非常重要 我试图理解MySQL datetime和timestamp中的时间戳类型,以及它们如何与Java代码和ISO8601时间字符串交互 我阅读了My

我意识到以前这里也有人问过类似的问题。但是我仍然需要为我的用例做更多的测试——我对结果有点惊讶/困惑

以下是测试代码和结果的说明

我正在开发一个应用程序:

记录在某个时间点发生的事件历史记录。 这段历史是一成不变的。一旦事件被写入,我们不会更改它。 我们报道这段历史。 计划未来可能重复的行动。例如,每周五做这项检查。 因此,对时间数据的清晰理解非常重要

我试图理解MySQL datetime和timestamp中的时间戳类型,以及它们如何与Java代码和ISO8601时间字符串交互

我阅读了MySQL文档中关于时间戳类型的内容——它如何将时间值转换为UTC存储,以及在检索时如何将UTC值转换为服务器或会话时区。这听起来像是一个很好的时间存储点

datetime MySQL类型有点不透明。本文认为它与字符串没有太大区别。 我重复了选择现在+0;查询并得到与文章相同的答案

为了澄清问题,我编写了一个小型Java类,它写入一个由3列组成的数据库表:

表示标准时区id的tz字符串。测试中使用UTC,但它不是时区。 mydatetime日期时间列 mytimestamp时间戳列 Java代码 Java代码位于此处:

测试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]
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]
从数据库中读取存储的时间

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]
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]
一切看起来都很好。当将历元秒放入类似的值时,它与ISO8601时间字符串一致

测试2 然后,我将MySQL服务器的时区从UTC+00:00更改为Europe/Amsterdam+02: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]
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列会受到影响——认为它没有存储时区信息。然而,移动的是Timestamp列

结论 我们不会定期更改服务器时区。 我正试图找出哪种MySQL数据类型最能代表一个时间点——我可以相信这种数据类型是准确的、不变的,而不是令人头痛的。基于上述情况,如果我以ISO8601字符串的形式提供时间点信息,Datetime MySQL类型将保留提供的信息

很有可能我的测试代码不正确和/或我对结果的解释不正确。 这里需要一点指导


在上面的测试用例中,Datetime MySQL类型在存储时间点信息方面做得更好吗?

经过进一步调整后,我得到了一个Java类,该类能够存储和检索时间点信息。我在这件事上还是有点紧张——很多人都想在这段时间里有发言权,这让我很不舒服

这门课是在原来的要点上进行的:修订显示了变化

我可以将MySQL服务器时区更改为任何我想要的。我还是把我放进去的东西拿出来。 直接在MySQL查询管理器中执行的查询也会起作用——时间戳列保持稳定。这就是我所期望的。 选择tz、mydatetime、unix_timestampmydatetime作为mydatetime,unix_timestampmytimestamp作为基本_时间; tz=时区id字符串;mydatetime日期时间列;mytimestamp时间戳列 时间戳MySQL类型是一个时间戳。我不需要搞砸它

Java 8 Java.sql.Timestamp类fromInstant和toInstant方法声明维护相同的时间点。 我在setObject和getObject preparedStatement方法上尝试了Instant。MySQL connector/J只是不接受它们——我深入查看了源代码。 Datetime MySQL类型我仍然有点困惑,因为我不知道它是什么,但知道时区我可以维护时间点信息

我尝试了MySQL连接器/J5.1.46和8.0.11版本。每个人都有相同的行为。 JDBC参数useLegacyDatetimeCode=false似乎很重要。我需要运行更多的测试,有没有这个来确认。
目前还不能完全分析这一点。试图弄明白这一点并不有趣。

最大的问题是JDBC驱动程序,当MySQL会话时区与JVM-Duser.timezone不匹配时,它会/试图对时区差异进行转换。使用MySQL Connector/J,各种看似奇怪的行为取决于useJDBCCompliantTimezoneShift、useLegacyDatetimeCode和serverTimezone的设置,以及MySQL数据类型的检测和到JDBC d的映射
数据类型。。。字符串和整数可以毫发无损地通过,但JDBC datetime类型可能会被屏蔽。还要注意,当会话时区与服务器全局时区不匹配时,MySQL会发生时区转换。@spencer7593-谢谢,我将更加小心地使用DB时区/JDBC时区/JVM时区对齐,并看看情况如何。令人沮丧的是,堆栈中有多少层需要对时区有意见;用于写入时间戳和rs.getObjectmytimestamp,用于读取它的Instant.class?假设您使用的JDBC 4.2至少已经为MySQL提供了多年,那么java.sql.Timestamp就没有用处了,而且该类早已过时。我还怀疑我提议的改变可能会改变你的结果,使之更符合你的预期。@OleV.V。嗯。试过了,在这里找到了你以前的信息。当我尝试您描述的setObject时,我得到错误的数据截断:不正确的日期时间值:'\xAC\xED\x00\x05sr\x00\x00\x0Djava.time.Ser\x95]\x84\xBA\x1BH\xB2\x0C\x00\x00xpw\x0D\x02\x00\x00\x00Z\xD0\x90\x80\x00\x00\x00\x00\x'作为第1行的“mytimestamp”列。datetime列上存在相同错误。我正在使用Java8和MySQL 5.7.18以及MySQL连接器/JV5.1.46。根据MySQL文档,此设置支持JDBC4.2