mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
merge revision(s) 3f07bc76ff
, 34098b669c
: [Backport #21144]
[Bug #21144] Win32: Use Windows time zone ID if TZ is not set If the TZ environment variable is not set, the time zone names retrieved from the system are localized for UI display and may vary across editions and language packs for the same time zone. Use the time zone IDs that are invariant across environments instead. [Bug #21144] Win32: Convert the time zone name to the current locale The Windows time zone IDs provided by Microsoft as of 24H1 are ASCII only all, but the API itself is not impossible to set non-ASCII key name. Prefer the current locale encoding for now until we move to UTF-8 including environment variables and command line arguments.
This commit is contained in:
parent
d635eb5156
commit
f7ec9546ee
4 changed files with 67 additions and 11 deletions
8
hash.c
8
hash.c
|
@ -4995,7 +4995,7 @@ env_name(volatile VALUE *s)
|
||||||
static VALUE env_aset(VALUE nm, VALUE val);
|
static VALUE env_aset(VALUE nm, VALUE val);
|
||||||
|
|
||||||
static void
|
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.
|
* ENV['TZ'] = nil has a special meaning.
|
||||||
|
@ -5004,7 +5004,7 @@ reset_by_modified_env(const char *nam)
|
||||||
* This hack might works only on Linux glibc.
|
* This hack might works only on Linux glibc.
|
||||||
*/
|
*/
|
||||||
if (ENVMATCH(nam, TZ_ENV)) {
|
if (ENVMATCH(nam, TZ_ENV)) {
|
||||||
ruby_reset_timezone();
|
ruby_reset_timezone(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5012,7 +5012,7 @@ static VALUE
|
||||||
env_delete(VALUE name)
|
env_delete(VALUE name)
|
||||||
{
|
{
|
||||||
const char *nam = env_name(name);
|
const char *nam = env_name(name);
|
||||||
reset_by_modified_env(nam);
|
reset_by_modified_env(nam, NULL);
|
||||||
VALUE val = getenv_with_lock(nam);
|
VALUE val = getenv_with_lock(nam);
|
||||||
|
|
||||||
if (!NIL_P(val)) {
|
if (!NIL_P(val)) {
|
||||||
|
@ -5472,7 +5472,7 @@ env_aset(VALUE nm, VALUE val)
|
||||||
get_env_ptr(value, val);
|
get_env_ptr(value, val);
|
||||||
|
|
||||||
ruby_setenv(name, value);
|
ruby_setenv(name, value);
|
||||||
reset_by_modified_env(name);
|
reset_by_modified_env(name, value);
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,10 @@ struct timeval rb_time_timeval(VALUE);
|
||||||
RUBY_SYMBOL_EXPORT_BEGIN
|
RUBY_SYMBOL_EXPORT_BEGIN
|
||||||
/* time.c (export) */
|
/* time.c (export) */
|
||||||
void ruby_reset_leap_second_info(void);
|
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
|
RUBY_SYMBOL_EXPORT_END
|
||||||
|
|
||||||
#endif /* INTERNAL_TIME_H */
|
#endif /* INTERNAL_TIME_H */
|
||||||
|
|
63
time.c
63
time.c
|
@ -44,6 +44,10 @@
|
||||||
#include "ruby/encoding.h"
|
#include "ruby/encoding.h"
|
||||||
#include "timev.h"
|
#include "timev.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
# include "timezoneapi.h" /* DYNAMIC_TIME_ZONE_INFORMATION */
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
|
||||||
static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
|
static ID id_submicro, id_nano_num, id_nano_den, id_offset, id_zone;
|
||||||
|
@ -701,10 +705,51 @@ static VALUE tm_from_time(VALUE klass, VALUE time);
|
||||||
|
|
||||||
bool ruby_tz_uptodate_p;
|
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
|
void
|
||||||
ruby_reset_timezone(void)
|
ruby_reset_timezone(const char *val)
|
||||||
{
|
{
|
||||||
ruby_tz_uptodate_p = false;
|
ruby_tz_uptodate_p = false;
|
||||||
|
#ifdef _WIN32
|
||||||
|
w32_tz.use_tzkey = !val || !*val;
|
||||||
|
#endif
|
||||||
ruby_reset_leap_second_info();
|
ruby_reset_leap_second_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -950,7 +995,13 @@ zone_str(const char *zone)
|
||||||
str = rb_usascii_str_new(zone, len);
|
str = rb_usascii_str_new(zone, len);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
#ifdef _WIN32
|
||||||
|
str = rb_utf8_str_new(zone, len);
|
||||||
|
/* until we move to UTF-8 on Windows completely */
|
||||||
|
str = rb_str_export_locale(str);
|
||||||
|
#else
|
||||||
str = rb_enc_str_new(zone, len, rb_locale_encoding());
|
str = rb_enc_str_new(zone, len, rb_locale_encoding());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return rb_fstring(str);
|
return rb_fstring(str);
|
||||||
}
|
}
|
||||||
|
@ -1652,11 +1703,9 @@ localtime_with_gmtoff_zone(const time_t *t, struct tm *result, long *gmtoff, VAL
|
||||||
if (zone) {
|
if (zone) {
|
||||||
#if defined(HAVE_TM_ZONE)
|
#if defined(HAVE_TM_ZONE)
|
||||||
*zone = zone_str(tm.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)
|
#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 */
|
/* this needs tzset or localtime, instead of localtime_r */
|
||||||
*zone = zone_str(tzname[daylight && tm.tm_isdst]);
|
*zone = zone_str(tzname[daylight && tm.tm_isdst]);
|
||||||
#else
|
#else
|
||||||
|
@ -5807,6 +5856,10 @@ rb_time_zone_abbreviation(VALUE zone, VALUE time)
|
||||||
void
|
void
|
||||||
Init_Time(void)
|
Init_Time(void)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
ruby_reset_timezone(getenv("TZ"));
|
||||||
|
#endif
|
||||||
|
|
||||||
id_submicro = rb_intern_const("submicro");
|
id_submicro = rb_intern_const("submicro");
|
||||||
id_nano_num = rb_intern_const("nano_num");
|
id_nano_num = rb_intern_const("nano_num");
|
||||||
id_nano_den = rb_intern_const("nano_den");
|
id_nano_den = rb_intern_const("nano_den");
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
# define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
|
||||||
#define RUBY_VERSION_TEENY 7
|
#define RUBY_VERSION_TEENY 7
|
||||||
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
#define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
|
||||||
#define RUBY_PATCHLEVEL 254
|
#define RUBY_PATCHLEVEL 255
|
||||||
|
|
||||||
#include "ruby/version.h"
|
#include "ruby/version.h"
|
||||||
#include "ruby/internal/abi.h"
|
#include "ruby/internal/abi.h"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue