summaryrefslogtreecommitdiff
path: root/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'time.c')
-rw-r--r--time.c57
1 files changed, 52 insertions, 5 deletions
diff --git a/time.c b/time.c
index d19d1873f8..56f93ec58d 100644
--- a/time.c
+++ b/time.c
@@ -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");