Java程式讀取時間比MySql時間早了8個小時
昨天碰見一個問題,需要從資料庫中讀取資料傳輸給其他平臺,從其他平臺檢視資料的時候發現時間不正確,多了8個小時,檢視接收日誌,接收到的時間是不正確,說明發送的時候應該就是不正確的,從傳送程式查,發現傳送的時候就是不正確的,而資料庫的時間是正確的,上網查了下,發現是連線資料庫的時候設定的時區不正確,連線資料庫時設定的是serverTimezone=UTC
,UTC是標準時間,比中國時間(東八區)時間早了8個小時,所以導致的不正確。網上的結論到這裡就結束了,感覺還少了一部分,又上網查了下java程式執行的時候也有自己的時區,如果不設定的話一般會從系統中取,如果設定資料庫的時區和系統時區一致,那沒有問題,如果時間不一致的話,就會出現問題。
獲取當前程式所用時區:
public static void main(String[] args) {
Calendar ca = Calendar.getInstance();
TimeZone tz = ca.getTimeZone();
System.out.println(tz.getID());
}
控制檯輸出:Asia/Shanghai
,而連線資料庫的時候設定的時區是serverTimezone=UTC
這時候就會出現問題,完整的流程應該是,程式從資料庫獲取時間,獲取時間的時候會看根據連線資料庫的時候設定的時區進行轉化,比如資料庫時間是2021-11-30 00:00:00,但是程式從資料庫取到後會比較兩者的時區,時區不一致時會進行轉化,UTC要比東八區慢八個小時,所以取到時間後會增加8個小時,獲取的時間是2021-11-30 08:00:00,到這裡算是一個完成流程。
將連線資料庫的serverTimezone設定為serverTimezone=Asia/Shanghai
serverTimezone=GMT%2B8
即可解決問題。
到這裡問題已經解決,後來看了下原始碼,程式會獲取系統時間,如果獲取不到的話會用預設時間GMT
,也是0時區。
下面是部分原始碼:
private static synchronized TimeZone setDefaultZone() { TimeZone tz; // get the time zone ID from the system properties String zoneID = AccessController.doPrivileged( new GetPropertyAction("user.timezone")); // if the time zone ID is not set (yet), perform the // platform to Java time zone ID mapping. if (zoneID == null || zoneID.isEmpty()) { String javaHome = AccessController.doPrivileged( new GetPropertyAction("java.home")); try { zoneID = getSystemTimeZoneID(javaHome); if (zoneID == null) { zoneID = GMT_ID; } } catch (NullPointerException e) { zoneID = GMT_ID; } } // Get the time zone for zoneID. But not fall back to // "GMT" here. tz = getTimeZone(zoneID, false); if (tz == null) { // If the given zone ID is unknown in Java, try to // get the GMT-offset-based time zone ID, // a.k.a. custom time zone ID (e.g., "GMT-08:00"). String gmtOffsetID = getSystemGMTOffsetID(); if (gmtOffsetID != null) { zoneID = gmtOffsetID; } tz = getTimeZone(zoneID, true); } assert tz != null; final String id = zoneID; AccessController.doPrivileged(new PrivilegedAction<Void>() { @Override public Void run() { System.setProperty("user.timezone", id); return null; } }); defaultTimeZone = tz; return tz; }
原始碼看到這裡的時候,已經有native方法了,搜了下,沒想到網上有大佬把呼叫的方法也寫出來了,Java讀取系統預設時區 ,這位老哥寫的確實挺全的,想看的同學可以看下。
金無足赤,人無完人,若有文章什麼問題歡迎各位批評指正,共同交流,共同進步。 另,人過留名,雁過留聲,少俠覺得還行的話留下個贊吧!:)