Java-带有SQL时间戳的时区转换问题

Java-带有SQL时间戳的时区转换问题,java,mysql,date,calendar,timezone,Java,Mysql,Date,Calendar,Timezone,我正在服务器上使用MySQL数据库。我的Web应用程序服务器位于美国/芝加哥,但我希望我的日期时间值保存在非洲/拉各斯时间 我从堆栈溢出中得到了部分代码,但当我更新记录时,它仍然在数据库记录中显示芝加哥时间。 请问我做错了什么 public static boolean saveImageFileName(int id, String fileName) throws SQLException, IOException, IllegalArgumentException, ClassNotFou

我正在服务器上使用MySQL数据库。我的Web应用程序服务器位于美国/芝加哥,但我希望我的日期时间值保存在非洲/拉各斯时间

我从堆栈溢出中得到了部分代码,但当我更新记录时,它仍然在数据库记录中显示芝加哥时间。 请问我做错了什么

public static boolean saveImageFileName(int id, String fileName) throws SQLException, IOException, IllegalArgumentException, ClassNotFoundException
{
    try(Connection conn = Config.getDatabaseConnection())
    {
        //Create a timezone object based on Africa/Lagos time zone
        SimpleTimeZone timeZone = new SimpleTimeZone(1, "Africa/Lagos");
        //Create a calendar object using the timezone object
        GregorianCalendar calendar = new GregorianCalendar(timeZone);
        //Create a timestamp object using the calendar's date and time
        Timestamp timestamp = new Timestamp(calendar.getTime().getTime());
        //Create an SQL query String
        String sql = "UPDATE `requests` SET `filename` = ?, `uploaded_date` = ? WHERE `id` = ?";
        //Create a prepared statement object from database connection
        PreparedStatement pst = conn.prepareStatement(sql);
        //Set prepared statement parameters
        pst.setString(1, fileName);
        pst.setTimestamp(2, timestamp, calendar); //Set TimeStamp and Calendar
        pst.setInt(3, id);
        //Update the record
        int update = pst.executeUpdate();
        //return update result
        return update == 1;
    }
}

您需要在
setTimeZone
方法中传递带有时区的
Calendar
对象,如javadoc中所述,请尝试以下操作:

pst.setTimestamp(2, timestamp, Calendar.getInstance(TimeZone.getTimeZone("Africa/Lagos"))); 
tl;博士 ……还有

Instant instant = myResultSet.getObject( 2 , Instant.class ) ;  // Stored moment in UTC.
ZonedDateTime zdt = instant.atZone( ZoneId.of( "Africa/Lagos" ) ) ;   // Adjust from UTC to time zone. Same moment, same point on timeline, but different wall-clock time.
不要依赖
toString
显然,您被遗留日期时间类的
toString
方法的输出弄糊涂了。在这些旧类中有许多糟糕的设计决策,其中一个是反特性,即应用JVM的当前时区,同时生成一个字符串以文本形式表示该日期时间对象的值。这会产生一种令人困惑的错觉,即对象有时区,而它没有时区

因此,不能在这些旧类上使用
toString
,因为它不能忠实地表示真实值

使用java.time 您使用的是麻烦的旧日期时间类,它们现在是遗留的,被java.time类取代

ZoneId z = ZoneId.of( "Africa/Lagos" ) ) ;
ZonedDateTime zdt = ZonedDateTime.now( zdt ) ;
但是时区在这里是不相关的,因为
java.sql.Timestamp
总是以UTC为单位。等价物是java.time中的
即时
。您可以从
ZonedDateTime
中提取
瞬间
,或将UTC中的当前时刻作为
瞬间

Instant instant = zdt.toInstant() ;  // Adjusting from a time zone to UTC.
或者

如果您的JDBC驱动程序符合JDBC 4.2或更高版本的要求,那么您可以直接使用java.time类型并放弃传统的java.sql类型。调用
PreparedStatement::setObject
ResultSet::getObject

如果您的JDBC尚未更新java.time,请使用添加到旧类中的新方法将其转换为
java.sql.Timestamp

java.sql.Timestamp ts = java.sql.Timestamp.from( instant ) ;
另一种方法是,当您想通过特定地区的挂钟时间镜头看到同一时刻时,可以将
瞬间
调整到特定时区

Instant instant = myResultSet.getObject( … , Instant.class )  // Or call: ts.toInstant()
ZonedDateTime zdt = instant.atZone( z ) ;

至于生成字符串对象以文本形式表示这些java.time对象的值,您可以依赖于调用
toString
方法。默认情况下,java.time类使用标准中定义的合理实用格式。

它仍然显示芝加哥时间2017-06-04 08:31:35,而不是2017-06-04 14:31:35
java.sql.Timestamp ts = java.sql.Timestamp.from( instant ) ;
Instant instant = myResultSet.getObject( … , Instant.class )  // Or call: ts.toInstant()
ZonedDateTime zdt = instant.atZone( z ) ;