我正在服务器上使用MySQL数据库。我的Web应用服务器在美国/芝加哥,但我希望我的DateTime值保存在非洲/拉各斯时间。
我从堆栈溢出中得到了部分代码,但是当我更新一个记录时,它仍然在数据库记录中显示芝加哥时间。
拜托,我在这里做错什么了?

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;
    }
}

最佳答案

tl;博士

pst.setObject( 2 , Instant.now() ) ;  // Current moment in UTC.

…还有…
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
显然,您对遗留日期时间类的输出感到困惑。在这些旧类中,有许多糟糕的设计决策,其中一个就是在生成字符串以文本方式表示日期时间对象的值时应用JVM当前时区的反特性。这就产生了一种令人困惑的错觉,即物体在没有时区的情况下有时区。
因此不能对那些旧类使用toString,因为它不能忠实地表示真正的值。
使用java.time
您正在使用麻烦的旧日期时间类,这些类现在是遗留的,已被java.time类取代。
ZoneId z = ZoneId.of( "Africa/Lagos" ) ) ;
ZonedDateTime zdt = ZonedDateTime.now( zdt ) ;

但是时区在这里是不相关的,因为toString总是在UTC中。等价于java.time中的ajava.sql.Timestamp。您可以从Instant中提取Instant或以ZonedDateTime的形式获取UTC中的当前时刻。
Instant instant = zdt.toInstant() ;  // Adjusting from a time zone to UTC.

或者…
Instant instant = Instant.now() ;  // Current moment in UTC.

如果JDBC驱动程序符合JDBC4.2或更高版本,则可以直接使用java.time类型并放弃旧的java.sql类型。呼叫InstantPreparedStatement::setObject
如果您的JDBC尚未更新java.time,请使用添加到旧类中的新方法转换为ResultSet::getObject
java.sql.Timestamp ts = java.sql.Timestamp.from( instant ) ;

另一方面,当你想通过一个特定区域的墙上时钟时间的镜头看到同一时刻时,你可以将一个java.sql.Timestamp调整到一个特定的时区。
Instant instant = myResultSet.getObject( … , Instant.class )  // Or call: ts.toInstant()
ZonedDateTime zdt = instant.atZone( z ) ;

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

07-24 18:27
查看更多