我在服务器上使用MySQL数据库。我的Web应用程序服务器位于美国/芝加哥,但我希望我的DateTime值保存在非洲/拉各斯时间。
我从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;
}
}
答案 0 :(得分:2)
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类。
ZoneId z = ZoneId.of( "Africa/Lagos" ) ) ;
ZonedDateTime zdt = ZonedDateTime.now( zdt ) ;
但是时区与此无关,因为java.sql.Timestamp
始终为UTC。等效于java.time中的Instant
。您可以从Instant
中提取ZonedDateTime
或以Instant
的形式获取UTC中的当前时刻。
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标准中定义的合理实用格式。
答案 1 :(得分:0)
您需要在Calendar
方法中使用TimeZone传递setTimeZone
对象,如this javadoc中所述,请尝试以下操作:
pst.setTimestamp(2, timestamp, Calendar.getInstance(TimeZone.getTimeZone("Africa/Lagos")));