auto merge of #10281 : klutzy/rust/rt-timezone, r=alexcrichton
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.
This commit is contained in:
commit
075347b445
@ -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");
|
||||
|
@ -330,11 +330,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user