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

如何将java.util.Date存储到UTC/GMT时区的MySQL时间戳字段中?,java,mysql,Java,Mysql,我使用了一个新的Date()对象来填充MySQL数据库中的一个字段,但该字段中存储的实际值在我的本地时区中 如何配置MySQL以将其存储在UTC/GMT时区 我认为,配置连接字符串会有所帮助,但我不知道如何配置。连接字符串中有许多属性,如useTimezone、serverTimzone、useGmtMillisForDatetimes、useLegacyDatetimeCode,…如果我们谈论的是使用PreparedStatements,那么您可以在其中将日历集传递到特定时区 例如,如果您有一

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

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


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

如果我们谈论的是使用
PreparedStatement
s,那么您可以在其中将日历集传递到特定时区

例如,如果您有一个名为stmt的PreparedStatement,一个名为Date的日期,并假设该日期是第二个参数:

stmt.setDate(2, date, Calendar.getInstance(TimeZone.getTimeZone("GMT")));
最好的部分是,即使GMT是无效的时区名称,由于getTimeZone的默认行为,它仍然返回GMT时区。

简短的回答是:

  • 将“默认时区=utc”添加到my.cnf
  • 在代码中,始终使用UTC“思考”,除非为用户显示日期
  • 使用JDBC获取/设置日期或时间戳时,始终使用日历参数,设置为UTC:

    resultset.getTimestamp(“我的约会”,Calendar.getInstance(TimeZone.getTimeZone(“UTC”))

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

长话短说的答案是:

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

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

    • 如何做到这一点取决于您的数据库服务器。有关MySQL的说明可在此处找到:。基本上,您需要在my.cnf:default time zone=utc中编写此代码

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

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

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

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

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

    • 或者,只依赖一台服务器来告诉您现在几点。通常,数据库服务器是最好的询问时间的服务器。换句话说,避免使用以下代码:

    preparedStatement=connection.prepareStatement(“更新我的_表设置我的_时间=?其中[…]);
    java.util.Date now=new java.util.Date();//本地时间!:-(
    preparedStatement.setTimestamp(1,新的时间戳(现在是.getTime());
    int result=preparedStatement.execute()

    • 相反,请依赖数据库服务器的时间:
    preparedStatement=connection.prepareStatement(“更新我的表格设置我的时间=NOW(),其中[…]);
    int result=preparedStatement.execute()


  • 希望这有帮助!:-)

    java日期是时区不可知的。它总是以GMD(UTC)表示一个日期,单位为从纪元算起的毫秒


    唯一的时间区是相关的,当你将日期作为字符串或解析数据串到DATA对象中时,

    MyQualk一般给出了一些很好的答案,但是有一些MySQL特有的怪癖要考虑……/P> 将数据库配置为使用UTC时区

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

    示例:如果将数据库配置为UTC,则您的应用程序为EST。您将传递一个5:00(EST)的java.util.Date对象。数据库将将其转换为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(“我的约会”,Calendar.getInstance(TimeZone.getTimeZone(“UTC”))


    MySql实际上忽略了该日历参数。无论您传递的是什么日历,它都会返回相同的值。

    我也遇到了同样的问题,我花了将近一天的时间才找到它。我正在MySql中存储DateTime列。运行在亚马逊云中的RDS实例默认情况下正确设置为具有UTC时间戳

    错误代码是:

        String startTime = "2013-02-01T04:00:00.000Z";
        DateTime dt = ISODateTimeFormat.dateTimeParser().parseDateTime(startTime);            
    
        PreparedStatement stmt = connection.prepareStatement(insertStatementTemplate);
    
        Timestamp ts = new Timestamp(dt.getMillis());
        stmt.setTimestamp(1, ts, Calendar.getInstance(TimeZone.getTimeZone("UTC"))); 
    
    在上面的代码中,“.setTimestamp”调用不会将日期作为UTC日期

    经过数小时的调查,这是Java/MySQL驱动程序中的一个已知错误
    private final static String DatabaseName =
      "jdbc:mysql://foo/?useLegacyDatetimeCode=false";