changeset 10693:98e3b24b7c0b

7044727: (tz) TimeZone.getDefault() call returns incorrect value in Windows terminal session Reviewed-by: naoto
author okutsu
date Mon, 20 Apr 2015 16:41:13 +0900
parents cd617abcb69e
children 88e71be7cc40
files src/windows/native/java/util/TimeZone_md.c
diffstat 1 files changed, 136 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/src/windows/native/java/util/TimeZone_md.c	Sun Apr 19 21:08:00 2015 +0300
+++ b/src/windows/native/java/util/TimeZone_md.c	Mon Apr 20 16:41:13 2015 +0900
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include "jvm.h"
 #include "TimeZone_md.h"
+#include "jdk_util.h"
 
 #define VALUE_UNKNOWN           0
 #define VALUE_KEY               1
@@ -49,6 +50,20 @@
     SYSTEMTIME  dstDate;
 } TziValue;
 
+#if _WIN32_WINNT < 0x0600 /* < _WIN32_WINNT_VISTA */
+typedef struct _TIME_DYNAMIC_ZONE_INFORMATION {
+    LONG        Bias;
+    WCHAR       StandardName[32];
+    SYSTEMTIME  StandardDate;
+    LONG        StandardBias;
+    WCHAR       DaylightName[32];
+    SYSTEMTIME  DaylightDate;
+    LONG        DaylightBias;
+    WCHAR       TimeZoneKeyName[128];
+    BOOLEAN     DynamicDaylightTimeDisabled;
+} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION;
+#endif
+
 /*
  * Registry key names
  */
@@ -143,6 +158,33 @@
 }
 
 /*
+ * Use NO_DYNAMIC_TIME_ZONE_INFO as the return value indicating that no
+ * dynamic time zone information is available.
+ */
+#define NO_DYNAMIC_TIME_ZONE_INFO     (-128)
+
+static int getDynamicTimeZoneInfo(PDYNAMIC_TIME_ZONE_INFORMATION pdtzi) {
+    DWORD timeType = NO_DYNAMIC_TIME_ZONE_INFO;
+    HMODULE dllHandle;
+
+    /*
+     * Dynamically load the dll to call GetDynamicTimeZoneInformation.
+     */
+    dllHandle = JDK_LoadSystemLibrary("Kernel32.dll");
+    if (dllHandle != NULL) {
+        typedef DWORD (WINAPI *GetDynamicTimezoneInfoType)(PDYNAMIC_TIME_ZONE_INFORMATION);
+        GetDynamicTimezoneInfoType getDynamicTimeZoneInfoFunc =
+            (GetDynamicTimezoneInfoType) GetProcAddress(dllHandle,
+                                                        "GetDynamicTimeZoneInformation");
+
+        if (getDynamicTimeZoneInfo != NULL) {
+            timeType = getDynamicTimeZoneInfoFunc(pdtzi);
+        }
+    }
+    return timeType;
+}
+
+/*
  * Gets the current time zone entry in the "Time Zones" registry.
  */
 static int getWinTimeZone(char *winZoneName, char *winMapID)
@@ -161,23 +203,96 @@
     WCHAR *stdNamePtr = tzi.StandardName;
     DWORD valueSize;
     DWORD timeType;
-    int isVista;
+    int isVistaOrLater;
 
     /*
-     * Get the current time zone setting of the platform.
+     * Determine if this is a Vista or later.
+     */
+    ver.dwOSVersionInfoSize = sizeof(ver);
+    GetVersionEx(&ver);
+    isVistaOrLater = (ver.dwMajorVersion >= 6);
+
+    if (isVistaOrLater) {
+        DYNAMIC_TIME_ZONE_INFORMATION dtzi;
+        DWORD bufSize;
+        DWORD val;
+
+        /*
+         * Get the dynamic time zone information, if available, so that time
+         * zone redirection can be supported. (see JDK-7044727)
+         */
+        timeType = getDynamicTimeZoneInfo(&dtzi);
+        if (timeType == TIME_ZONE_ID_INVALID) {
+            goto err;
+        }
+
+        if (timeType != NO_DYNAMIC_TIME_ZONE_INFO) {
+            /*
+             * Make sure TimeZoneKeyName is available from the API call. If
+             * DynamicDaylightTime is disabled, return a custom time zone name
+             * based on the GMT offset. Otherwise, return the TimeZoneKeyName
+             * value.
+             */
+            if (dtzi.TimeZoneKeyName[0] != 0) {
+                if (dtzi.DynamicDaylightTimeDisabled) {
+                    customZoneName(dtzi.Bias, winZoneName);
+                    return VALUE_GMTOFFSET;
+                }
+                wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR);
+                return VALUE_KEY;
+            }
+
+            /*
+             * If TimeZoneKeyName is not available, check whether StandardName
+             * is available to fall back to the older API GetTimeZoneInformation.
+             * If not, directly read the value from registry keys.
+             */
+            if (dtzi.StandardName[0] == 0) {
+                ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
+                                   KEY_READ, (PHKEY)&hKey);
+                if (ret != ERROR_SUCCESS) {
+                    goto err;
+                }
+
+                /*
+                 * Determine if auto-daylight time adjustment is turned off.
+                 */
+                bufSize = sizeof(val);
+                ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
+                                       &valueType, (LPBYTE) &val, &bufSize);
+                if (ret != ERROR_SUCCESS) {
+                    goto err;
+                }
+                /*
+                 * Return a custom time zone name if auto-daylight time
+                 * adjustment is disabled.
+                 */
+                if (val == 1) {
+                    customZoneName(dtzi.Bias, winZoneName);
+                    (void) RegCloseKey(hKey);
+                    return VALUE_GMTOFFSET;
+                }
+
+                bufSize = MAX_ZONE_CHAR;
+                ret = RegQueryValueExA(hKey, "TimeZoneKeyName",NULL,
+                                       &valueType, (LPBYTE)winZoneName, &bufSize);
+                if (ret != ERROR_SUCCESS) {
+                    goto err;
+                }
+                (void) RegCloseKey(hKey);
+                return VALUE_KEY;
+            }
+        }
+    }
+
+    /*
+     * Fall back to GetTimeZoneInformation
      */
     timeType = GetTimeZoneInformation(&tzi);
     if (timeType == TIME_ZONE_ID_INVALID) {
         goto err;
     }
 
-    /*
-     * Determine if this is an NT system.
-     */
-    ver.dwOSVersionInfoSize = sizeof(ver);
-    GetVersionEx(&ver);
-    isVista = ver.dwMajorVersion >= 6;
-
     ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0,
                        KEY_READ, (PHKEY)&hKey);
     if (ret == ERROR_SUCCESS) {
@@ -187,23 +302,23 @@
         /*
          * Determine if auto-daylight time adjustment is turned off.
          */
-        valueType = 0;
         bufSize = sizeof(val);
-        ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet",
-                               NULL, &valueType, (LPBYTE) &val, &bufSize);
-        /*
-         * Vista uses the different key name.
-         */
+        ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL,
+                               &valueType, (LPBYTE) &val, &bufSize);
         if (ret != ERROR_SUCCESS) {
+            /*
+             * Try the old key name.
+             */
             bufSize = sizeof(val);
-            ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled",
-                                   NULL, &valueType, (LPBYTE) &val, &bufSize);
+            ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet", NULL,
+                                   &valueType, (LPBYTE) &val, &bufSize);
         }
 
         if (ret == ERROR_SUCCESS) {
-            int daylightSavingsUpdateDisabledOther = val == 1 && tzi.DaylightDate.wMonth != 0;
-            int daylightSavingsUpdateDisabledVista = val == 1;
-            int daylightSavingsUpdateDisabled = isVista ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther;
+            int daylightSavingsUpdateDisabledOther = (val == 1 && tzi.DaylightDate.wMonth != 0);
+            int daylightSavingsUpdateDisabledVista = (val == 1);
+            int daylightSavingsUpdateDisabled
+                = (isVistaOrLater ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther);
 
             if (daylightSavingsUpdateDisabled) {
                 (void) RegCloseKey(hKey);
@@ -213,28 +328,12 @@
         }
 
         /*
-         * Vista has the key for the current "Time Zones" entry.
-         */
-        if (isVista) {
-            valueType = 0;
-            bufSize = MAX_ZONE_CHAR;
-            ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL,
-                                   &valueType, (LPBYTE) winZoneName, &bufSize);
-            if (ret != ERROR_SUCCESS) {
-                goto err;
-            }
-            (void) RegCloseKey(hKey);
-            return VALUE_KEY;
-        }
-
-        /*
          * Win32 problem: If the length of the standard time name is equal
          * to (or probably longer than) 32 in the registry,
          * GetTimeZoneInformation() on NT returns a null string as its
          * standard time name. We need to work around this problem by
          * getting the same information from the TimeZoneInformation
-         * registry. The function on Win98 seems to return its key name.
-         * We can't do anything in that case.
+         * registry.
          */
         if (tzi.StandardName[0] == 0) {
             bufSize = sizeof(stdNameInReg);