当前位置: 首页 > 知识库问答 >
问题:

当服务器时区不是UTC时,在Java中从MySQL检索UTC DATETIME字段

仲涵亮
2023-03-14

我正在尝试编写代码,以便使用Java和MySQL与第三方开发的数据库进行互操作。此数据库有一个字段,该字段将datetime字段中的时间戳存储为UTC日期。运行数据库和客户端的服务器的时区被设置为非UTC区(Europe/London),因此默认情况下,时间戳被错误地读回,就像它是本地时间一样。我正在尝试编写代码以UTC的形式读回它。

我在这里读过几个类似的问题,但没有一个对我有效的答案:

  • MySQL-如何用正确的时区存储时间?(来自Java)
  • 如何将java.util.Date存储到UTC/GMT时区中的MySQL时间戳字段中?
  • MySQL中的UTC日期
  • 如何设置MySQL的时区?

不幸的是,我无法更改任何服务器设置,因此我尝试使用连接的“time_zone”变量将数据库服务器设置为使用UTC,并将可选的Calendar参数设置为ResultSet.GetTimestamp来检索日期,但这对结果没有影响。下面是我的代码:

private static final Calendar UTCCALENDAR = Calendar.getInstance (TimeZone.getTimeZone (ZoneOffset.UTC));
public Date getDate ()
{
    try (Connection c = dataSource.getConnection ();
         PreparedStatement s = c
             .prepareStatement ("select datefield from dbmail_datefield where physmessage_id=?"))
    {
        fixTimeZone (c);
        s.setLong (1, getPhysId ());
        try (ResultSet rs = s.executeQuery ())
        {
            if (!rs.next ()) return null;
            return new Date (rs.getTimestamp(1,UTCCALENDAR).getTime ());    // do not use SQL timestamp object, as it fucks up comparisons!
        }
    }
    catch (SQLException e)
    {
        throw new MailAccessException ("Error accessing dbmail database", e);
    }
}

private void fixTimeZone (Connection c)
{
    try (Statement s = c.createStatement ())
    {
        s.executeUpdate ("set time_zone='+00:00'");
    }
    catch (SQLException e)
    {
        throw new MailAccessException ("Unable to set SQL connection time zone to UTC", e);
    }
}

我试图读取的数据库字段中存储了一个值,如下所示:

myhtml" target="_blank">sql> select * from dbmail_datefield where physmessage_id=494539;
+----------------+--------+---------------------+
| physmessage_id | id     | datefield           |
+----------------+--------+---------------------+
|         494539 | 494520 | 2015-04-16 10:30:30 |
+----------------+--------+---------------------+

但不幸的是,结果显示为BST而不是UTC:

java.lang.AssertionError: expected:<Thu Apr 16 11:30:30 BST 2015> but was:<Thu Apr 16 10:30:30 BST 2015>

共有1个答案

夏侯楷
2023-03-14

您的客户机getdate()代码看起来是正确的。我认为您还需要使用MySQL Connector/J JDBC驱动程序来将存储在表中的日期作为UTC日期处理,以避免错误的时区转换。这意味着设置有效的服务器时区,以及用于JDBCGetTimestamp调用的客户端会话时区和日历。

看看在失败的断言中得到的值,以及错误在哪个方向:

expected:<Thu Apr 16 11:30:30 BST 2015> but was:<Thu Apr 16 10:30:30 BST 2015>

你得到的是英国夏令时10点30分,也就是格林尼治时间9点30分。这与数据库将表中的10:30视为BST值并在您将其解析为GMT日期之前将其虚假地转换为GMT是一致的。这与被错误地转换为BST的GMT值的方向相反。

这可能是一个特定于JDBC的问题,因为JDBC要求将time times转换到本地区域。(而MySQL C API却没有,这可能是因为C的经典时间类型不像Java那样具有区域感知性。)它还需要知道它从什么区域转换。MySQLtimestamp类型始终存储为UTC。但对于datetime类型没有说明这一点。我认为这意味着MySQL将datetime列值解释为在服务器的时区中。这与断言错误消息中显示的移动方向是一致的。

您设置的time_zone会话变量告诉MySQL服务器您的客户机的时区是什么,但它不影响服务器认为自己的时区是什么。可以使用ServerTimeZoneJDBC连接属性重写。在连接上,将ServerTimeZone设置为UTC,并确保UselegacyDateTimeCode关闭。(如果不起作用,则查看其他与区域相关的属性。)看看这是否使您的日期以UTC的形式出现,并与数据库中的日历字段值相同。

请注意,这将改变数据库中其他datetime值的解释:它们现在看起来都像UTC日期(在JDBC连接的上下文中)。这是否正确将取决于它们最初是如何填充的。虽然您的客户机代码将具有您想要的行为,但我不知道在服务器级别上不将服务器的时区设置为UTC的情况下,是否可以使系统作为一个整体保持完全一致的行为。基本上,如果它的区域没有设置为UTC,那么它就没有为您想要的行为完全配置,您就会绕过它。

 类似资料:
  • 问题内容: 我正在考虑在用户登录时将日期存储在我的网站中,但是我不知道什么是最合乎逻辑的解决方案。 最初,我虽然使用服务器时区,然后使用服务器计算机日期和用户计算机日期之间的差异操作来管理它,但是我也考虑过使用时区和php类日期来更改它的准确性,因此: 我的问题是,最好的解决方案是保留服务器时区还是使用用户时区? 如果我使用用户时区,是否也应像示例中那样保存时区名称? 问题答案: 我建议使用服务器

  • 我试图通过json从在线数据库(MySql)获取数据,并希望将其显示为ListView。到目前为止我所做的: Downloader.java } 美娜ctivity.java 当我运行应用程序时,应用程序。。在Downloader.java类的第35行,我收到一条toast消息,上面写着“无法下载数据”。所以我猜我从数据库中得到的数据是空的…但为什么是空的。。。。 $con=mysqli_conn

  • 我正试图从ftp服务器检索一个文件,但我得到如下错误。请你帮帮我好吗 导入java.io.BufferedOutputStream; 导入java.io.file; 导入java.io.FileOutputStream; 导入java.io.IOException; 导入java.io.InputStream; 导入java.io.OutputStream; 导入java.text.DateFor

  • 问题内容: 在我的Java程序中,我需要创建当前时刻的实例。我用 这给了我根据主机系统时钟的当前日期和时间。有什么办法可以从在线服务器获取当前日期和时间?世界时间服务器? 我看过篇文章,它描述了我想要的内容,但是我恐怕需要比那里提供的更多帮助。 简而言之,我想获得一个不依赖于主机系统时钟的日期和时间。 谢谢! 问题答案: 您可以在以下位置查看Java NTP客户端演示 http://www.doc

  • 服务器成功启动并接受数据,但当我检索数据时,却出现以下错误: O.a.c.c.[.[/].[dispatcherServlet]:路径为[]的上下文 中servlet[dispatcherServlet]的servlet.Service()引发异常[请求处理失败;嵌套异常为 org.springframework.data.MongoDb.UncategorizedMongoDbException