From 5116789aa0abcf731aaad883ea99d79844b66a85 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 31 Jul 2019 19:20:03 +0900 Subject: Fix UTC offset representation in `Time#to_s` on some environments; ref #4604 Use own implementation to calculate UTC offset on Visual Studio 2015 or earlier or MinGW because `strftime("%z")` on these environments does not conform C99. --- mrbgems/mruby-time/src/time.c | 43 ++++++++++++++++++++++++++++++++--------- mrbgems/mruby-time/test/time.rb | 3 ++- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c index e3b5d3fe7..0d144c4e7 100644 --- a/mrbgems/mruby-time/src/time.c +++ b/mrbgems/mruby-time/src/time.c @@ -926,20 +926,45 @@ mrb_time_utc_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(tm->timezone == MRB_TIMEZONE_UTC); } +static size_t +time_to_s_utc(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len) +{ + return strftime(buf, buf_len, TO_S_FMT "UTC", &tm->datetime); +} + +static size_t +time_to_s_local(mrb_state *mrb, struct mrb_time *tm, char *buf, size_t buf_len) +{ +#if defined(_MSC_VER) && _MSC_VER < 1900 || defined(__MINGW64__) || defined(__MINGW32__) + struct tm datetime = {0}; + time_t utc_sec = timegm(&tm->datetime); + size_t len; + int offset; + + if (utc_sec == (time_t)-1) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "Not a valid time."); + } + offset = abs((int)(utc_sec - tm->sec) / 60); + datetime.tm_year = 100; + datetime.tm_hour = offset / 60; + datetime.tm_min = offset % 60; + len = strftime(buf, buf_len, TO_S_FMT, &tm->datetime); + buf[len++] = utc_sec < tm->sec ? '-' : '+'; + + return len + strftime(buf + len, buf_len - len, "%H%M", &datetime); +#else + return strftime(buf, buf_len, TO_S_FMT "%z", &tm->datetime); +#endif +} + static mrb_value mrb_time_to_s(mrb_state *mrb, mrb_value self) { char buf[64]; struct mrb_time *tm = time_get_ptr(mrb, self); - const char *fmt = tm->timezone == MRB_TIMEZONE_UTC ? TO_S_FMT "UTC" : TO_S_FMT "%z"; - size_t len = strftime(buf, sizeof(buf), fmt, &tm->datetime); - char *utf8; - mrb_value mrb_string; - buf[len] = '\0'; - utf8 = mrb_utf8_from_locale(buf, (int)len); - mrb_string = mrb_str_new_cstr(mrb, utf8); - mrb_utf8_free(utf8); - return mrb_string; + mrb_bool utc = tm->timezone == MRB_TIMEZONE_UTC; + size_t len = (utc ? time_to_s_utc : time_to_s_local)(mrb, tm, buf, sizeof(buf)); + return mrb_str_new(mrb, buf, len); } void diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb index f59e27bc1..be1de7bc6 100644 --- a/mrbgems/mruby-time/test/time.rb +++ b/mrbgems/mruby-time/test/time.rb @@ -239,7 +239,8 @@ assert('Time#to_s') do end assert('Time#inspect') do - assert_match("2013-10-28 16:27:48 [^U]*", Time.local(2013,10,28,16,27,48).inspect) + assert_match("2013-10-28 16:27:48 [+-][0-9][0-9][0-9][0-9]", + Time.local(2013,10,28,16,27,48).inspect) end assert('day of week methods') do -- cgit v1.2.3