如何将java.util.Date存储在UTC / GMT时区的MySQL时间戳字段中?

2022-09-03 14:12:38

我使用了一个新的Date()对象来填充MySQL数据库中的字段,但该字段中存储的实际值是我的本地时区。

如何配置MySQL以将其存储在UTC / GMT时区?

我认为,配置连接字符串会有所帮助,但我不知道如何操作。连接字符串中有许多属性,例如 useTimezone、serverTimzone、useGmtMillisForDatetimes、useLegacyDatetimeCode、...


答案 1

简短的回答是:

  • 将“default-time-zone=utc”添加到 my.cnf
  • 在代码中,始终以 UTC 格式“思考”,除非为用户显示日期
  • 使用 JDBC 获取/设置日期或时间戳时,请始终使用 Calendar 参数,设置为 UTC:

    resultset.getTimestamp(“my_date”, Calendar.getInstance(TimeZone.getTimeZone(“UTC”)));

  • 要么将服务器与 NTP 同步,要么仅依靠数据库服务器来告诉您现在是什么时间。

长答案是这样的:

在处理任何数据库中的日期和时区以及任何客户端代码时,我通常建议使用以下策略:

  1. 将数据库配置为使用 UTC 时区,而不是使用服务器的本地时区(当然,除非它是 UTC)。

    • 如何执行此操作取决于您的数据库服务器。可以在此处找到MySQL的说明:http://dev.mysql.com/doc/refman/5.0/en/time-zone-support.html。基本上你需要在my.cnf中写这个:default-time-zone=utc

    • 通过这种方式,您可以在任何地方托管数据库服务器,轻松更改托管位置,并且更普遍地操作服务器上的日期,而不会有任何歧义。

    • 如果您真的喜欢使用本地时区,我建议至少关闭夏令时,因为数据库中的日期不明确可能是一场真正的噩梦。
      • 例如,如果您正在构建电话服务,并且您在数据库服务器上使用夏令时,那么您就是在自找麻烦:无法判断从“2008-10-26 02:30:00”呼叫到“2008-10-26 02:35:00”的客户是否确实呼叫了 5 分钟或 1 小时 5 分钟(假设夏令时发生在 10 月 26 日凌晨 3 点)!
  2. 在应用程序代码中,始终使用 UTC 日期,除非向用户显示日期。

    • 在 Java 中,从数据库读取时,请始终使用:

    Timestamp myDate = resultSet.getTimestamp(“my_date”, Calendar.getInstance(TimeZone.getTimeZone(“UTC”)));

    • 如果不这样做,时间戳将假定为本地时区,而不是 UTC。
  3. 同步服务器或仅依赖数据库服务器的时间

    • 如果您的 Web 服务器位于一台(或多台)服务器上,数据库服务器位于其他服务器上,那么我强烈建议您将它们的时钟与 NTP 同步。

    • 或者,只依靠一台服务器来告诉你现在是什么时间。通常,数据库服务器是请求时间的最佳服务器。换句话说,避免这样的代码:

    preparedStatement = connection.prepareStatement(“UPDATE my_table SET my_time = ?其中[...]“);
    java.util.Date now = new java.util.Date();当地时间!:-(
    preparedStatement.setTimestamp(1, new Timestamp(now.getTime()));
    int result = preparedStatement.execute();

    • 相反,请依赖数据库服务器的时间:

    preparedStatement = connection.prepareStatement(“UPDATE my_table SET my_time = NOW() WHERE [...]”);
    int result = preparedStatement.execute();

希望这有帮助!:-)


答案 2

MiniQuark总体上为数据库提供了一些很好的答案,但是有一些MySql特定的怪癖需要考虑......

将数据库配置为使用 UTC 时区

这实际上不足以解决问题。如果按照 OP 的要求将 java.util.Date 传递给 MySql,则 MySql 驱动程序将更改该值,使其看起来像数据库时区中的相同本地时间。

示例:您的数据库(如果配置为 UTC)。您的应用程序是 EST。您将 java.util.Date 对象传递给 5:00 (EST)。数据库会将其转换为 5:00 UTC 并存储它。棒。

在传递数据以“撤消”此自动调整之前,您必须调整时间。像这样...

long originalTime = originalDate.getTime();
Date newDate = new Date(originalTime - TimeZone.getDefault().getOffset(originalTime));
ps.setDate(1, newDate);

读回数据需要类似的转换。

long dbTime = rs.getTimestamp(1).getTime();
Date originalDate = new Date(dbTime + TimeZone.getDefault().getOffset(dbTime));

这是另一个有趣的怪癖...

在Java中,当从数据库中读取时,始终使用:Timestamp myDate = resultSet.getTimestamp(“my_date”, Calendar.getInstance(TimeZone.getTimeZone(“UTC”)));

MySql实际上忽略了该日历参数。这将返回相同的值,而不管您传递哪个日历。


推荐