Java-带有SQL时间戳的时区转换问题
我正在服务器上使用MySQL数据库。我的Web应用程序服务器位于美国/芝加哥,但我希望我的日期时间值保存在非洲/拉各斯时间 我从堆栈溢出中得到了部分代码,但当我更新记录时,它仍然在数据库记录中显示芝加哥时间。 请问我做错了什么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
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 ) ;