2017-06-04 31 views
1

我在服务器上使用MySQL数据库。我的Web应用程序服务器位于美国/芝加哥但我希望将我的DateTime值保存在非洲/拉各斯时间。Java - 使用SQL时间戳的TimeZone转换问题

我从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

你需要通过与时区Calendar对象setTimeZone方法,如this javadoc中提到,试试这个:

pst.setTimestamp(2, timestamp, Calendar.getInstance(TimeZone.getTimeZone("Africa/Lagos"))); 
+0

它仍然显示芝加哥时间2017-06-04 08:31:35而不是2017-06-04 14:31:35 – Jevison7x

2

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

显然,你正在由传统的日期 - 时间班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::setObjectResultSet::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标准中定义的合理的实际格式。