diff options
-rw-r--r-- | hash.c | 8 | ||||
-rw-r--r-- | internal/time.h | 5 | ||||
-rw-r--r-- | time.c | 57 |
3 files changed, 60 insertions, 10 deletions
@@ -5016,7 +5016,7 @@ env_name(volatile VALUE *s) static VALUE env_aset(VALUE nm, VALUE val); static void -reset_by_modified_env(const char *nam) +reset_by_modified_env(const char *nam, const char *val) { /* * ENV['TZ'] = nil has a special meaning. @@ -5025,7 +5025,7 @@ reset_by_modified_env(const char *nam) * This hack might works only on Linux glibc. */ if (ENVMATCH(nam, TZ_ENV)) { - ruby_reset_timezone(); + ruby_reset_timezone(val); } } @@ -5033,7 +5033,7 @@ static VALUE env_delete(VALUE name) { const char *nam = env_name(name); - reset_by_modified_env(nam); + reset_by_modified_env(nam, NULL); VALUE val = getenv_with_lock(nam); if (!NIL_P(val)) { @@ -5439,7 +5439,7 @@ env_aset(VALUE nm, VALUE val) get_env_ptr(value, val); ruby_setenv(name, value); - reset_by_modified_env(name); + reset_by_modified_env(name, value); return val; } diff --git a/internal/time.h b/internal/time.h index a3bf0587ec..e21b3574f6 100644 --- a/internal/time.h +++ b/internal/time.h @@ -28,7 +28,10 @@ struct timeval rb_time_timeval(VALUE); RUBY_SYMBOL_EXPORT_BEGIN /* time.c (export) */ void ruby_reset_leap_second_info(void); -void ruby_reset_timezone(void); +#ifdef RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY +RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() +#endif +void ruby_reset_timezone(const char *); RUBY_SYMBOL_EXPORT_END #endif /* INTERNAL_TIME_H */ @@ -45,6 +45,10 @@ #include "ruby/util.h" #include "timev.h" +#if defined(_WIN32) +# include "timezoneapi.h" /* DYNAMIC_TIME_ZONE_INFORMATION */ +#endif + #include "builtin.h" static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone; @@ -703,10 +707,51 @@ static VALUE tm_from_time(VALUE klass, VALUE time); bool ruby_tz_uptodate_p; +#ifdef _WIN32 +enum {tzkey_max = numberof(((DYNAMIC_TIME_ZONE_INFORMATION *)NULL)->TimeZoneKeyName)}; +static struct { + char use_tzkey; + char name[tzkey_max * 4 + 1]; +} w32_tz; + +static char * +get_tzname(int dst) +{ + if (w32_tz.use_tzkey) { + if (w32_tz.name[0]) { + return w32_tz.name; + } + else { + /* + * Use GetDynamicTimeZoneInformation::TimeZoneKeyName, Windows + * time zone ID, which is not localized because it is the key + * for "Dynamic DST" keys under the "Time Zones" registry. + * Available since Windows Vista and Windows Server 2008. + */ + DYNAMIC_TIME_ZONE_INFORMATION tzi; + WCHAR *const wtzkey = tzi.TimeZoneKeyName; + DWORD tzret = GetDynamicTimeZoneInformation(&tzi); + if (tzret != TIME_ZONE_ID_INVALID && *wtzkey) { + int wlen = (int)wcsnlen(wtzkey, tzkey_max); + int clen = WideCharToMultiByte(CP_UTF8, 0, wtzkey, wlen, + w32_tz.name, sizeof(w32_tz.name) - 1, + NULL, NULL); + w32_tz.name[clen] = '\0'; + return w32_tz.name; + } + } + } + return _tzname[_daylight && dst]; +} +#endif + void -ruby_reset_timezone(void) +ruby_reset_timezone(const char *val) { ruby_tz_uptodate_p = false; +#ifdef _WIN32 + w32_tz.use_tzkey = !val || !*val; +#endif ruby_reset_leap_second_info(); } @@ -1653,11 +1698,9 @@ localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, VAL if (zone) { #if defined(HAVE_TM_ZONE) *zone = zone_str(tm.tm_zone); +#elif defined(_WIN32) + *zone = zone_str(get_tzname(tm.tm_isdst)); #elif defined(HAVE_TZNAME) && defined(HAVE_DAYLIGHT) -# if defined(RUBY_MSVCRT_VERSION) && RUBY_MSVCRT_VERSION >= 140 -# define tzname _tzname -# define daylight _daylight -# endif /* this needs tzset or localtime, instead of localtime_r */ *zone = zone_str(tzname[daylight && tm.tm_isdst]); #else @@ -5863,6 +5906,10 @@ rb_time_zone_abbreviation(VALUE zone, VALUE time) void Init_Time(void) { +#ifdef _WIN32 + ruby_reset_timezone(getenv("TZ")); +#endif + id_submicro = rb_intern_const("submicro"); id_nano_num = rb_intern_const("nano_num"); id_nano_den = rb_intern_const("nano_den"); |