From e63ffc1d1677e31c8978d13a87811c9ee19e5927 Mon Sep 17 00:00:00 2001 From: klutzy Date: Tue, 5 Nov 2013 13:20:04 +0900 Subject: [PATCH 1/2] rt: Convert timezone to utf-8 on Windows Previously #9418 fixed utf-8 assertion issue by wcsftime, but the function didn't work as expected: it follows the locale set by setlocale(), not the system code page. This patch fixes it by manual multibyte-to-unicode conversion. --- src/rt/rust_builtin.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 90cfd98bc4859..c1a1eefb841c4 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -325,11 +325,16 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { const char* zone = NULL; #if defined(__WIN32__) int32_t gmtoff = -timezone; - wchar_t wbuffer[64]; - char buffer[256]; + wchar_t wbuffer[64] = {0}; + char buffer[256] = {0}; // strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418), - // so time zone should be converted from UTF-16 string set by wcsftime. - if (wcsftime(wbuffer, sizeof(wbuffer) / sizeof(wchar_t), L"%Z", &tm) > 0) { + // so time zone should be converted from UTF-16 string. + // Since wcsftime depends on setlocale() result, + // instead we convert it using MultiByteToWideChar. + if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) { + // ANSI -> UTF-16 + MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t)); + // UTF-16 -> UTF-8 WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL); zone = buffer; } From fe18fe0f884ab4edb2b0a986b68572b361285599 Mon Sep 17 00:00:00 2001 From: klutzy Date: Wed, 6 Nov 2013 09:55:31 +0900 Subject: [PATCH 2/2] extra::time: Fix test on Windows Closes #10307 --- src/libextra/time.rs | 99 ++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 40 deletions(-) diff --git a/src/libextra/time.rs b/src/libextra/time.rs index 2950f02ad19dd..eff0da96bffba 100644 --- a/src/libextra/time.rs +++ b/src/libextra/time.rs @@ -965,8 +965,35 @@ mod tests { use super::*; use std::f64; - use std::os; use std::result::{Err, Ok}; + use std::libc; + + #[cfg(windows)] + #[fixed_stack_segment] + fn set_time_zone() { + // Windows crt doesn't see any environment variable set by + // `SetEnvironmentVariable`, which `os::setenv` internally uses. + // It is why we use `putenv` here. + extern { + fn _putenv(envstring: *libc::c_char) -> libc::c_int; + } + + unsafe { + // Windows does not understand "America/Los_Angeles". + // PST+08 may look wrong, but not! "PST" indicates + // the name of timezone. "+08" means UTC = local + 08. + do "TZ=PST+08".with_c_str |env| { + _putenv(env); + } + } + tzset(); + } + #[cfg(not(windows))] + fn set_time_zone() { + use std::os; + os::setenv("TZ", "America/Los_Angeles"); + tzset(); + } fn test_get_time() { static SOME_RECENT_DATE: i64 = 1325376000i64; // 2012-01-01T00:00:00Z @@ -1007,57 +1034,54 @@ mod tests { } fn test_at_utc() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); - assert!(utc.tm_sec == 30_i32); - assert!(utc.tm_min == 31_i32); - assert!(utc.tm_hour == 23_i32); - assert!(utc.tm_mday == 13_i32); - assert!(utc.tm_mon == 1_i32); - assert!(utc.tm_year == 109_i32); - assert!(utc.tm_wday == 5_i32); - assert!(utc.tm_yday == 43_i32); - assert!(utc.tm_isdst == 0_i32); - assert!(utc.tm_gmtoff == 0_i32); - assert!(utc.tm_zone == ~"UTC"); - assert!(utc.tm_nsec == 54321_i32); + assert_eq!(utc.tm_sec, 30_i32); + assert_eq!(utc.tm_min, 31_i32); + assert_eq!(utc.tm_hour, 23_i32); + assert_eq!(utc.tm_mday, 13_i32); + assert_eq!(utc.tm_mon, 1_i32); + assert_eq!(utc.tm_year, 109_i32); + assert_eq!(utc.tm_wday, 5_i32); + assert_eq!(utc.tm_yday, 43_i32); + assert_eq!(utc.tm_isdst, 0_i32); + assert_eq!(utc.tm_gmtoff, 0_i32); + assert_eq!(utc.tm_zone, ~"UTC"); + assert_eq!(utc.tm_nsec, 54321_i32); } fn test_at() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let local = at(time); error!("time_at: {:?}", local); - assert!(local.tm_sec == 30_i32); - assert!(local.tm_min == 31_i32); - assert!(local.tm_hour == 15_i32); - assert!(local.tm_mday == 13_i32); - assert!(local.tm_mon == 1_i32); - assert!(local.tm_year == 109_i32); - assert!(local.tm_wday == 5_i32); - assert!(local.tm_yday == 43_i32); - assert!(local.tm_isdst == 0_i32); - assert!(local.tm_gmtoff == -28800_i32); + assert_eq!(local.tm_sec, 30_i32); + assert_eq!(local.tm_min, 31_i32); + assert_eq!(local.tm_hour, 15_i32); + assert_eq!(local.tm_mday, 13_i32); + assert_eq!(local.tm_mon, 1_i32); + assert_eq!(local.tm_year, 109_i32); + assert_eq!(local.tm_wday, 5_i32); + assert_eq!(local.tm_yday, 43_i32); + assert_eq!(local.tm_isdst, 0_i32); + assert_eq!(local.tm_gmtoff, -28800_i32); // FIXME (#2350): We should probably standardize on the timezone // abbreviation. let zone = &local.tm_zone; assert!(*zone == ~"PST" || *zone == ~"Pacific Standard Time"); - assert!(local.tm_nsec == 54321_i32); + assert_eq!(local.tm_nsec, 54321_i32); } fn test_to_timespec() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); @@ -1067,8 +1091,7 @@ mod tests { } fn test_conversions() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); @@ -1083,8 +1106,7 @@ mod tests { } fn test_strptime() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); match strptime("", "") { Ok(ref tm) => { @@ -1248,8 +1270,7 @@ mod tests { } fn test_ctime() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); @@ -1262,8 +1283,7 @@ mod tests { } fn test_strftime() { - os::setenv("TZ", "America/Los_Angeles"); - tzset(); + set_time_zone(); let time = Timespec::new(1234567890, 54321); let utc = at_utc(time); @@ -1323,8 +1343,7 @@ mod tests { // abbreviation. let rfc822 = local.rfc822(); let prefix = ~"Fri, 13 Feb 2009 15:31:30 "; - assert!(rfc822 == prefix + "PST" || - rfc822 == prefix + "Pacific Standard Time"); + assert!(rfc822 == prefix + "PST" || rfc822 == prefix + "Pacific Standard Time"); assert_eq!(local.ctime(), ~"Fri Feb 13 15:31:30 2009"); assert_eq!(local.rfc822z(), ~"Fri, 13 Feb 2009 15:31:30 -0800");