我在服务器上使用 MySQL 数据库。我的 Web 应用程序服务器位于 US/Chicago,但我希望我的 DateTime 值以Africa/Lagos 时间保存。
我从 Stack Overflow 获得了这段代码的一部分,但是当我更新一条记录时,它仍然在数据库记录中显示芝加哥时间。 请问我在这里做错了什么?
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;dr
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
显然,您对遗留日期时间类的 toString
方法的输出感到困惑。在这些旧类的许多糟糕的设计决策中,有一个反特征是应用 JVM 的当前时区,同时生成一个字符串来以文本方式表示该日期时间对象的值。这会产生一种令人困惑的错觉,即该对象有一个时区,而实际上它没有。
因此您不能在那些旧类上使用 toString
,因为它不能忠实地表示真实值。
使用java.time
您正在使用麻烦的旧日期时间类,这些类现在已成为遗留问题,已被 java.time 类取代。
ZoneId z = ZoneId.of( "Africa/Lagos" ) ) ;
ZonedDateTime zdt = ZonedDateTime.now( zdt ) ;
但这里时区无关紧要,因为 java.sql.Timestamp
始终采用 UTC。等效于 java.time 中的 Instant
。您可以从 ZonedDateTime
中提取 Instant
或获取 UTC 中的当前时刻作为 Instant
。
Instant instant = zdt.toInstant() ; // Adjusting from a time zone to UTC.
或者……
Instant instant = Instant.now() ; // Current moment in 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 instant = myResultSet.getObject( … , Instant.class ) // Or call: ts.toInstant()
ZonedDateTime zdt = instant.atZone( z ) ;
至于生成 String 对象以文本方式表示这些 java.time 对象的值,您可以依赖于调用 toString
方法。默认情况下,java.time 类使用 ISO 8601 中定义的合理实用格式。标准。
关于Java - SQL时间戳的时区转换问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44354478/