OpenJDK / jdk8u / jdk8u / jdk
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);