在 Java 中处理 MySQL 日期时间和时间戳

Posted

技术标签:

【中文标题】在 Java 中处理 MySQL 日期时间和时间戳【英文标题】:Handling MySQL datetimes and timestamps in Java 【发布时间】:2011-03-20 09:54:20 【问题描述】:

在 java 应用程序中,在使用日期时间和时间戳的混合使用 mysql 数据库提取和输入日期信息方面,什么是好的折衷方案?

【问题讨论】:

【参考方案1】:

MySQL documentation 包含有关将 MySQL 类型映射到 Java 类型的信息。一般来说,对于 MySQL 日期时间和时间戳,您应该使用java.sql.Timestamp。一些资源包括:

http://dev.mysql.com/doc/refman/5.1/en/datetime.html

http://www.coderanch.com/t/304851/JDBC/java/Java-date-MySQL-date-conversion

How to store Java Date to Mysql datetime...?

http://www.velocityreviews.com/forums/t599436-the-best-practice-to-deal-with-datetime-in-mysql-using-jdbc.html

编辑:

正如其他人所指出的,使用字符串的建议可能会导致问题。

【讨论】:

为什么将日期转换为字符串会更好? 不要像绳子一样来回按摩它。这是可移植性和可维护性问题的根源。 同意。我已经相应地修改了我的答案。【参考方案2】:

在 Java 方面,日期通常由(设计不佳,但除此之外)java.util.Date 表示。它基本上由Epoch time 支持,类似于long,也称为时间戳。它包含有关日期和时间部分的信息。在 Java 中,精度以毫秒为单位。

在 SQL 端,有几种标准的日期和时间类型,DATETIMETIMESTAMP(在某些 DB 中也称为 DATETIME),它们在 JDBC 中表示为 java.sql.Date、@987654324 @ 和 java.sql.Timestampjava.util.Date 的所有子类。精度取决于 DB,通常像 Java 一样以毫秒为单位,但也可以以秒为单位。

java.util.Date 不同,java.sql.Date 仅包含有关日期部分(年、月、日)的信息。 Time 仅包含有关时间部分(小时、分钟、秒)的信息,Timestamp 包含有关这两个部分的信息,就像 java.util.Date 一样。

在数据库中存储时间戳(因此,Java 端为java.util.Date,JDBC 端为java.sql.Timestamp)的常规做法是使用PreparedStatement#setTimestamp()

java.util.Date date = getItSomehow();
Timestamp timestamp = new Timestamp(date.getTime());
preparedStatement = connection.prepareStatement("SELECT * FROM tbl WHERE ts > ?");
preparedStatement.setTimestamp(1, timestamp);

从数据库获取时间戳的常规做法是使用ResultSet#getTimestamp()

Timestamp timestamp = resultSet.getTimestamp("ts");
java.util.Date date = timestamp; // You can just upcast.

【讨论】:

你觉得在模型(Java层)中使用java.sql.Timestamp不好么? @cherouvim:是的。该模型不应该知道任何 JDBC 细节。仅用于设置时间戳。 preparedStatement.setTimestamp(new Timestamp(date.getTime()));。获取它很容易,因为它已经是 java.util.Date 的子类。 如果您的所有机器和用户都在同一个时区,这将正常工作。否则,请注意 MySQL JDBC 驱动程序对时区转换的处理非常复杂和错误。例如见***.com/questions/40670532/… BalusC,在您看来,我应该为 DB 内的列使用什么类型(日期/时间戳?)。按照您的示例,当我从 DB 读取时,我收到类似 2017-01-24 19:17:11.0 的信息,但在 2017 年 1 月 24 日星期二 19:17:11 EET 之前。此外,当我使用 compareTo 进行比较时,我得到:之前> 之后。附言我在数据库中使用时间戳 @Sabine:你有一个带时区的时间戳。并非所有数据库都支持此功能。例如。 PostgreSQL 和 Oracle 可以,但 MySQL 不行。在保存到数据库之前,您需要转换为固定时区。通常使用 UTC。【参考方案3】:

BalusC 对问题给出了很好的描述,但它缺乏用户可以自己挑选和测试的良好端到端代码。

最佳做法是始终将日期时间存储在数据库中的 UTC 时区中。 Sql 时间戳类型没有时区信息。

将日期时间值写入 sql db 时

    //Convert the time into UTC and build Timestamp object.
    Timestamp ts = Timestamp.valueOf(LocalDateTime.now(ZoneId.of("UTC")));
    //use setTimestamp on preparedstatement
    preparedStatement.setTimestamp(1, ts);

当从 DB 读回值到 java 中时,

    按 java.sql.Timestamp 类型读取。 使用 atZone 将 DateTime 值装饰为 UTC 时区中的时间 LocalDateTime 类中的方法。

    然后,将其更改为您想要的时区。在这里,我将其更改为 多伦多时区。

    ResultSet resultSet = preparedStatement.executeQuery();
    resultSet.next();
    Timestamp timestamp = resultSet.getTimestamp(1);
    ZonedDateTime timeInUTC = timestamp.toLocalDateTime().atZone(ZoneId.of("UTC"));
    LocalDateTime timeInToronto = LocalDateTime.ofInstant(timeInUTC.toInstant(), ZoneId.of("America/Toronto"));
    

【讨论】:

以上是关于在 Java 中处理 MySQL 日期时间和时间戳的主要内容,如果未能解决你的问题,请参考以下文章

php日期转时间戳

如何从java中的字符串时间戳中提取日期和时间

mysql5.5时间戳能不能精确到毫秒?

在Java中打印两个时间戳之间的日期时间

MySQL中日期和时间戳互相转换的函数和方法

MySQL中from_unixtime和unix_timestamp处理数据库时间戳转换问题-案例