Java 可以通過 Timezone 獲取時區,但是通過 Timezone 獲取的時區是 JVM 初始化時保存的時區,並不是操作系統所設置的時區。當修改過操作系統的時區后,JVM 並不會同步更新。Timezone 獲取時區的代碼如下:
// 獲取 JVM 啟動時獲取的時區 TimeZone.getDefault(); // 獲取任意指定區域的時區 String[] zoneIDs = TimeZone.getAvailableIDs(); for(String zoneID: zoneIDs) { TimeZone.getTimeZone(zoneID); }
當修改了操作系統的時區后,但JVM 並不會同步更新,因此直接通過 Timezone 獲取默認時區並不是修改后的時區。若要程序獲取修改后的操作系統時區,則可以這樣修改:
// 將獲取默認時區的兩個前置條件設置為 false, 令其獲取系統時間,原理見后面分析 synchronized (TimeZone.class) { TimeZone.setDefault(null); System.setProperty("user.timezone", ""); TimeZone.getDefault(); }
這么做的原因是,我們需要調用Timezone 的本地方法 getSystemTimeZoneID(String javaHome),請看源碼
/** * Returns the reference to the default TimeZone object. This * method doesn't create a clone. */ static TimeZone getDefaultRef() { TimeZone defaultZone = defaultTimeZone; if (defaultZone == null) { // Need to initialize the default time zone. defaultZone = setDefaultZone(); assert defaultZone != null; } // Don't clone here. return defaultZone; } 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); // 重點,這個方法就是我們需要調用的,但是 Timezone 並沒有對外提供接口訪問該方法,因此只能將前置條件改為 false, 令程序調用該方法即可獲取操作系統的時間。 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; }
轉自:https://blog.csdn.net/zhaoxj_2017/article/details/99676852