2017-03-28 37 views
3

我在那裏我存儲從傳感器MySQL的選擇日期時間不夏令時的變化

CREATE TABLE `testdatabase` (
    `dateTime` datetime DEFAULT NULL, 
    `data` varchar(200) DEFAULT NULL, 
    `sensorID` varchar(10) DEFAULT NULL 
    PRIMARY KEY (`id`) 
) ENGINE=InnoDB AUTO_INCREMENT=6918 DEFAULT CHARSET=utf8 

這是我運行的是選擇查詢的數據表,

SELECT `dateTime` from testdatabase WHERE sensorID='ABC1234' AND (dateTime BETWEEN '2017-03-26 00:01:00' AND '2017-03-26 00:00:00') order by `dateTime` asc; 

在MySQL工作臺,當我運行此查詢,它會返回正確的日期時間。

2017-03-26 00:10:00 
2017-03-26 00:20:00 
2017-03-26 00:30:00 
2017-03-26 00:40:00 
2017-03-26 00:50:00 
2017-03-26 01:00:00 
2017-03-26 01:10:00 
2017-03-26 01:20:00 
2017-03-26 01:30:00 
2017-03-26 01:40:00 
2017-03-26 01:50:00 
2017-03-26 02:00:00 
2017-03-26 02:10:00 
2017-03-26 02:20:00 
2017-03-26 02:30:00 
2017-03-26 02:40:00 
2017-03-26 02:50:00 
2017-03-26 03:00:00 

但是,當我從我的Java應用程序運行此查詢時,它會返回以下日期時間。

2017-03-26 00:10:00 
2017-03-26 00:20:00 
2017-03-26 00:30:00 
2017-03-26 00:40:00 
2017-03-26 00:50:00 
2017-03-26 02:00:00 
2017-03-26 02:10:00 
2017-03-26 02:20:00 
2017-03-26 02:30:00 
2017-03-26 02:40:00 
2017-03-26 02:50:00 
2017-03-26 02:00:00 
2017-03-26 02:10:00 
2017-03-26 02:20:00 
2017-03-26 02:30:00 
2017-03-26 02:40:00 
2017-03-26 02:50:00 
2017-03-26 03:00:00 

很明顯,這與英國發生在3月26日凌晨1點的DST變化有關。 我認爲JDBC連接正在改變BST的時間,但我不希望這樣。

我試圖MySQL服務器全球時區設置爲00:00

SET @@global.time_zone='+00:00'; 

但沒有成功! 如何在沒有DST更改的情況下獲得正確的時間?

編輯: 我使用Java 1.7mysql-connector-java-5.1.19-bin.jar

我得到的數據爲字符串之前,但之後Mark Rotteveel評論我試着PreparedStaement設置爲UTC日曆對象,但都返回相同的結果。

try 
{ 
    Statement statement = connection.createStatement(); 
    ResultSet resultSet = statement.executeQuery(query); 
    while(resultSet.next()) 
    { 
     System.out.println("Without Calendar Object : "+resultSet.getString(1)); 
    } 
}catch (SQLException e){e.printStackTrace();} 

try 
{ 
    PreparedStatement statement = connection.prepareStatement(query); 
    ResultSet resultSet = statement.executeQuery(); 
    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
    while(resultSet.next()) 
    { 
     System.out.println("With Calendar Object : "+resultSet.getTimestamp(1, cal)); 
    } 
}catch (SQLException e){e.printStackTrace();} 

OUTPUT: 
    Without Calendar Object : 2017-03-26 00:10:00.0 
    Without Calendar Object : 2017-03-26 00:20:00.0 
    Without Calendar Object : 2017-03-26 00:30:00.0 
    Without Calendar Object : 2017-03-26 00:40:00.0 
    Without Calendar Object : 2017-03-26 00:50:00.0 
    Without Calendar Object : 2017-03-26 02:00:00.0 
    Without Calendar Object : 2017-03-26 02:10:00.0 
    Without Calendar Object : 2017-03-26 02:20:00.0 
    Without Calendar Object : 2017-03-26 02:30:00.0 
    Without Calendar Object : 2017-03-26 02:40:00.0 
    Without Calendar Object : 2017-03-26 02:50:00.0 
    Without Calendar Object : 2017-03-26 02:00:00.0 
    Without Calendar Object : 2017-03-26 02:10:00.0 
    Without Calendar Object : 2017-03-26 02:20:00.0 
    Without Calendar Object : 2017-03-26 02:30:00.0 
    Without Calendar Object : 2017-03-26 02:40:00.0 
    Without Calendar Object : 2017-03-26 02:50:00.0 
    Without Calendar Object : 2017-03-26 03:00:00.0 
    With Calendar Object : 2017-03-26 00:10:00.0 
    With Calendar Object : 2017-03-26 00:20:00.0 
    With Calendar Object : 2017-03-26 00:30:00.0 
    With Calendar Object : 2017-03-26 00:40:00.0 
    With Calendar Object : 2017-03-26 00:50:00.0 
    With Calendar Object : 2017-03-26 02:00:00.0 
    With Calendar Object : 2017-03-26 02:10:00.0 
    With Calendar Object : 2017-03-26 02:20:00.0 
    With Calendar Object : 2017-03-26 02:30:00.0 
    With Calendar Object : 2017-03-26 02:40:00.0 
    With Calendar Object : 2017-03-26 02:50:00.0 
    With Calendar Object : 2017-03-26 02:00:00.0 
    With Calendar Object : 2017-03-26 02:10:00.0 
    With Calendar Object : 2017-03-26 02:20:00.0 
    With Calendar Object : 2017-03-26 02:30:00.0 
    With Calendar Object : 2017-03-26 02:40:00.0 
    With Calendar Object : 2017-03-26 02:50:00.0 
    With Calendar Object : 2017-03-26 03:00:00.0 

編輯2: 有,當我更改默認的時區爲UTC它凌晨1點,而不是凌晨2時返回重複值,另一個奇怪的事情。

TimeZone.setDefault(TimeZone.getTimeZone("UTC")); 

OUTPUT:

Without Calendar Object : 2017-03-26 00:10:00.0 
Without Calendar Object : 2017-03-26 00:20:00.0 
Without Calendar Object : 2017-03-26 00:30:00.0 
Without Calendar Object : 2017-03-26 00:40:00.0 
Without Calendar Object : 2017-03-26 00:50:00.0 
Without Calendar Object : 2017-03-26 01:00:00.0 
Without Calendar Object : 2017-03-26 01:10:00.0 
Without Calendar Object : 2017-03-26 01:20:00.0 
Without Calendar Object : 2017-03-26 01:30:00.0 
Without Calendar Object : 2017-03-26 01:40:00.0 
Without Calendar Object : 2017-03-26 01:50:00.0 
Without Calendar Object : 2017-03-26 01:00:00.0 
Without Calendar Object : 2017-03-26 01:10:00.0 
Without Calendar Object : 2017-03-26 01:20:00.0 
Without Calendar Object : 2017-03-26 01:30:00.0 
Without Calendar Object : 2017-03-26 01:40:00.0 
Without Calendar Object : 2017-03-26 01:50:00.0 
Without Calendar Object : 2017-03-26 02:00:00.0 
With Calendar Object : 2017-03-26 00:10:00.0 
With Calendar Object : 2017-03-26 00:20:00.0 
With Calendar Object : 2017-03-26 00:30:00.0 
With Calendar Object : 2017-03-26 00:40:00.0 
With Calendar Object : 2017-03-26 00:50:00.0 
With Calendar Object : 2017-03-26 01:00:00.0 
With Calendar Object : 2017-03-26 01:10:00.0 
With Calendar Object : 2017-03-26 01:20:00.0 
With Calendar Object : 2017-03-26 01:30:00.0 
With Calendar Object : 2017-03-26 01:40:00.0 
With Calendar Object : 2017-03-26 01:50:00.0 
With Calendar Object : 2017-03-26 01:00:00.0 
With Calendar Object : 2017-03-26 01:10:00.0 
With Calendar Object : 2017-03-26 01:20:00.0 
With Calendar Object : 2017-03-26 01:30:00.0 
With Calendar Object : 2017-03-26 01:40:00.0 
With Calendar Object : 2017-03-26 01:50:00.0 
With Calendar Object : 2017-03-26 02:00:00.0 
+0

查看http://stackoverflow.com/questions/14070572/is-java-sql-timestamp-timezone-specific/14070771#14070771 –

+0

@MarkRotteveel在這個問題中,數據類型是時間戳,但我的表有一個日期時間的數據類型,我的印象是隻有時間戳存儲時區值,日期時間不存儲此信息 – Ana

+0

不要將JDBC數據類型與MySQL數據類型混淆。 'Types.TIMESTAMP'(或'java.sql.Timestamp')沒有時區,但是當從數據庫中檢索一個沒有時區信息的數據類型的值時(例如MySQLs'datetime'),JDBC需要它會在當前的JVM時區中解釋,除非您使用'getTimestamp'來獲取帶有時區信息的'Calendar'對象。 –

回答

1

有兩個問題在這裏打球:

  1. 我們是否想要的java.sql.Timestamp值從服務器返回的?
  2. 當我們要求Java將Timestamp值顯示爲日期/時間字符串時,我們實際看到了什麼?

爲了解決這個問題,我們可以顯示其數值形式的Timestamp值。 Timestamp#getTime()返回自紀元(1970-01-01 00:00:00 UTC)以來的毫秒數,但如果我們將它除以60000以給出自紀元以來的分鐘數,我們可以使其更容易閱讀。

我們還可以使用SimpleDateFormat對象以明確的方式格式化Timestamp值。

所以名爲tztest一個示例表,看起來像這樣在phpMyAdmin

id dateTime 
-- ------------------- 
1 2017-03-26 00:10:00 
2 2017-03-26 01:10:00 
3 2017-03-26 02:10:00 

,當我跑下面的Java代碼

connectionUrl = "jdbc:mysql://localhost:3307/mydb"; 
try (Connection conn = DriverManager.getConnection(connectionUrl, myUid, myPwd)) { 
    SimpleDateFormat sdfLocal = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); 
    Calendar calUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 
    SimpleDateFormat sdfUTC = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); 
    sdfUTC.setCalendar(calUTC); 
    String sql = 
      "SELECT id, CAST(dateTime AS CHAR) AS datetimeString, dateTime " + 
      "FROM tztest ORDER BY dateTime"; 
    try ( Statement st = conn.createStatement(); 
      ResultSet rs = st.executeQuery(sql)) { 
     while (rs.next()) { 
      int id = rs.getInt("id"); 
      String datetimeString = rs.getString("datetimeString"); 
      Timestamp timestampValue = rs.getTimestamp("dateTime", calUTC); 
      long minutesSinceEpoch = timestampValue.getTime()/60000; 
      System.out.printf("%d: %s -> %d minutes since epoch -> %s/%s%n", 
        id, 
        datetimeString, 
        minutesSinceEpoch, 
        sdfLocal.format(timestampValue), 
        sdfUTC.format(timestampValue) 
        ); 
     } 
    } 
} catch (Exception e) { 
    e.printStackTrace(System.err); 
} 

控制檯輸出爲

1: 2017-03-26 00:10:00 -> 24841450 minutes since epoch -> 2017-03-26 00:10:00 GMT/2017-03-26 00:10:00 UTC 
2: 2017-03-26 01:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST/2017-03-26 01:10:00 UTC 
3: 2017-03-26 02:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST/2017-03-26 01:10:00 UTC 

顯然自從我沒有獲得期望的Timestamp值第2行和第3行都顯示「自紀元以來的24841510分鐘」。

我能夠通過簡單地添加useLegacyDatetimeCode=false我的連接字符串

connectionUrl = "jdbc:mysql://localhost:3307/mydb?useLegacyDatetimeCode=false"; 

之後,控制檯輸出爲

1: 2017-03-26 00:10:00 -> 24841450 minutes since epoch -> 2017-03-26 00:10:00 GMT/2017-03-26 00:10:00 UTC 
2: 2017-03-26 01:10:00 -> 24841510 minutes since epoch -> 2017-03-26 02:10:00 BST/2017-03-26 01:10:00 UTC 
3: 2017-03-26 02:10:00 -> 24841570 minutes since epoch -> 2017-03-26 03:10:00 BST/2017-03-26 02:10:00 UTC 

注意,第3行現在顯示「紀元以來24841570分鐘」糾正,比第2行晚60分鐘。還要注意,UTC格式的日期時間值與我們在SQL查詢中使用CAST(dateTime AS CHAR)時得到的字符串表示形式相匹配。

+0

謝謝Gord ...在連接字符串中添加'useLegacyDatetimeCode = false'解決了這個問題,你的例子有所幫助。我還有一個問題,java將兩種('timestamp'和'datetime')MySQL數據類型當作時間戳嗎?因爲在我的數據庫表中,數據類型是datetime,但是當我在ResultSet對象中獲取數據時,它的類是timestamp('resultSet.getObject(1).getClass()。getName()= java.sql.timestamp') – Ana

+0

默認情況下,MySQL Connector/J會將'DATETIME'列和'TIMESTAMP'列的值作爲'java.sql.Timestamp'對象返回。但是,它不會更改MySQL數據庫中這些列類型的行爲。 MySQL'TIMESTAMP'列和'java.sql.Timestamp'對象共享相同的「時間戳」名稱的事實實際上只是巧合。 –