blob: 80de8fa2c2b416ac188761cb1040af32e1784ad1 [file] [log] [blame]
#![allow(bad_style)]
pub use self::inner::*;
#[cfg(any(
all(target_arch = "wasm32", not(target_os = "emscripten")),
target_env = "sgx"
))]
mod common {
use Tm;
pub fn time_to_tm(ts: i64, tm: &mut Tm) {
let leapyear = |year| -> bool {
year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
};
static _ytab: [[i64; 12]; 2] = [
[ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ],
[ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]
];
let mut year = 1970;
let dayclock = ts % 86400;
let mut dayno = ts / 86400;
tm.tm_sec = (dayclock % 60) as i32;
tm.tm_min = ((dayclock % 3600) / 60) as i32;
tm.tm_hour = (dayclock / 3600) as i32;
tm.tm_wday = ((dayno + 4) % 7) as i32;
loop {
let yearsize = if leapyear(year) {
366
} else {
365
};
if dayno >= yearsize {
dayno -= yearsize;
year += 1;
} else {
break;
}
}
tm.tm_year = (year - 1900) as i32;
tm.tm_yday = dayno as i32;
let mut mon = 0;
while dayno >= _ytab[if leapyear(year) { 1 } else { 0 }][mon] {
dayno -= _ytab[if leapyear(year) { 1 } else { 0 }][mon];
mon += 1;
}
tm.tm_mon = mon as i32;
tm.tm_mday = dayno as i32 + 1;
tm.tm_isdst = 0;
}
pub fn tm_to_time(tm: &Tm) -> i64 {
let mut y = tm.tm_year as i64 + 1900;
let mut m = tm.tm_mon as i64 + 1;
if m <= 2 {
y -= 1;
m += 12;
}
let d = tm.tm_mday as i64;
let h = tm.tm_hour as i64;
let mi = tm.tm_min as i64;
let s = tm.tm_sec as i64;
(365*y + y/4 - y/100 + y/400 + 3*(m+1)/5 + 30*m + d - 719561)
* 86400 + 3600 * h + 60 * mi + s
}
}
#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
mod inner {
use std::ops::{Add, Sub};
use Tm;
use Duration;
use super::common::{time_to_tm, tm_to_time};
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct SteadyTime;
pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
time_to_tm(sec, tm);
}
pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
// FIXME: Add timezone logic
time_to_tm(sec, tm);
}
pub fn utc_tm_to_time(tm: &Tm) -> i64 {
tm_to_time(tm)
}
pub fn local_tm_to_time(tm: &Tm) -> i64 {
// FIXME: Add timezone logic
tm_to_time(tm)
}
pub fn get_time() -> (i64, i32) {
unimplemented!()
}
pub fn get_precise_ns() -> u64 {
unimplemented!()
}
impl SteadyTime {
pub fn now() -> SteadyTime {
unimplemented!()
}
}
impl Sub for SteadyTime {
type Output = Duration;
fn sub(self, _other: SteadyTime) -> Duration {
unimplemented!()
}
}
impl Sub<Duration> for SteadyTime {
type Output = SteadyTime;
fn sub(self, _other: Duration) -> SteadyTime {
unimplemented!()
}
}
impl Add<Duration> for SteadyTime {
type Output = SteadyTime;
fn add(self, _other: Duration) -> SteadyTime {
unimplemented!()
}
}
}
#[cfg(target_env = "sgx")]
mod inner {
use std::ops::{Add, Sub};
use Tm;
use Duration;
use super::common::{time_to_tm, tm_to_time};
use std::time::SystemTime;
/// The number of nanoseconds in seconds.
const NANOS_PER_SEC: u64 = 1_000_000_000;
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct SteadyTime {
t: Duration
}
pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
time_to_tm(sec, tm);
}
pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
// FIXME: Add timezone logic
time_to_tm(sec, tm);
}
pub fn utc_tm_to_time(tm: &Tm) -> i64 {
tm_to_time(tm)
}
pub fn local_tm_to_time(tm: &Tm) -> i64 {
// FIXME: Add timezone logic
tm_to_time(tm)
}
pub fn get_time() -> (i64, i32) {
SteadyTime::now().t.raw()
}
pub fn get_precise_ns() -> u64 {
// This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system
// clock is adjusted backward.
let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
std_duration.as_secs() * NANOS_PER_SEC + std_duration.subsec_nanos() as u64
}
impl SteadyTime {
pub fn now() -> SteadyTime {
// This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system
// clock is adjusted backward.
let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap();
// This unwrap is safe because duration is well within the limits of i64.
let duration = Duration::from_std(std_duration).unwrap();
SteadyTime { t: duration }
}
}
impl Sub for SteadyTime {
type Output = Duration;
fn sub(self, other: SteadyTime) -> Duration {
self.t - other.t
}
}
impl Sub<Duration> for SteadyTime {
type Output = SteadyTime;
fn sub(self, other: Duration) -> SteadyTime {
SteadyTime { t: self.t - other }
}
}
impl Add<Duration> for SteadyTime {
type Output = SteadyTime;
fn add(self, other: Duration) -> SteadyTime {
SteadyTime { t: self.t + other }
}
}
}
#[cfg(unix)]
mod inner {
use libc::{self, time_t};
use std::mem;
use std::io;
use Tm;
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub use self::mac::*;
#[cfg(all(not(target_os = "macos"), not(target_os = "ios")))]
pub use self::unix::*;
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
extern {
static timezone: time_t;
static altzone: time_t;
}
fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) {
tm.tm_sec = rust_tm.tm_sec;
tm.tm_min = rust_tm.tm_min;
tm.tm_hour = rust_tm.tm_hour;
tm.tm_mday = rust_tm.tm_mday;
tm.tm_mon = rust_tm.tm_mon;
tm.tm_year = rust_tm.tm_year;
tm.tm_wday = rust_tm.tm_wday;
tm.tm_yday = rust_tm.tm_yday;
tm.tm_isdst = rust_tm.tm_isdst;
}
fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) {
rust_tm.tm_sec = tm.tm_sec;
rust_tm.tm_min = tm.tm_min;
rust_tm.tm_hour = tm.tm_hour;
rust_tm.tm_mday = tm.tm_mday;
rust_tm.tm_mon = tm.tm_mon;
rust_tm.tm_year = tm.tm_year;
rust_tm.tm_wday = tm.tm_wday;
rust_tm.tm_yday = tm.tm_yday;
rust_tm.tm_isdst = tm.tm_isdst;
rust_tm.tm_utcoff = utcoff;
}
#[cfg(any(target_os = "nacl", target_os = "solaris", target_os = "illumos"))]
unsafe fn timegm(tm: *mut libc::tm) -> time_t {
use std::env::{set_var, var_os, remove_var};
extern {
fn tzset();
}
let ret;
let current_tz = var_os("TZ");
set_var("TZ", "UTC");
tzset();
ret = libc::mktime(tm);
if let Some(tz) = current_tz {
set_var("TZ", tz);
} else {
remove_var("TZ");
}
tzset();
ret
}
pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
unsafe {
let sec = sec as time_t;
let mut out = mem::zeroed();
if libc::gmtime_r(&sec, &mut out).is_null() {
panic!("gmtime_r failed: {}", io::Error::last_os_error());
}
tm_to_rust_tm(&out, 0, tm);
}
}
pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
unsafe {
let sec = sec as time_t;
let mut out = mem::zeroed();
if libc::localtime_r(&sec, &mut out).is_null() {
panic!("localtime_r failed: {}", io::Error::last_os_error());
}
#[cfg(any(target_os = "solaris", target_os = "illumos"))]
let gmtoff = {
::tzset();
// < 0 means we don't know; assume we're not in DST.
if out.tm_isdst == 0 {
// timezone is seconds west of UTC, tm_gmtoff is seconds east
-timezone
} else if out.tm_isdst > 0 {
-altzone
} else {
-timezone
}
};
#[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
let gmtoff = out.tm_gmtoff;
tm_to_rust_tm(&out, gmtoff as i32, tm);
}
}
pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 {
#[cfg(all(target_os = "android", target_pointer_width = "32"))]
use libc::timegm64 as timegm;
#[cfg(not(any(
all(target_os = "android", target_pointer_width = "32"),
target_os = "nacl",
target_os = "solaris",
target_os = "illumos"
)))]
use libc::timegm;
let mut tm = unsafe { mem::zeroed() };
rust_tm_to_tm(rust_tm, &mut tm);
unsafe { timegm(&mut tm) as i64 }
}
pub fn local_tm_to_time(rust_tm: &Tm) -> i64 {
let mut tm = unsafe { mem::zeroed() };
rust_tm_to_tm(rust_tm, &mut tm);
unsafe { libc::mktime(&mut tm) as i64 }
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod mac {
#[allow(deprecated)]
use libc::{self, timeval, mach_timebase_info};
#[allow(deprecated)]
use std::sync::{Once, ONCE_INIT};
use std::ops::{Add, Sub};
use Duration;
#[allow(deprecated)]
fn info() -> &'static mach_timebase_info {
static mut INFO: mach_timebase_info = mach_timebase_info {
numer: 0,
denom: 0,
};
static ONCE: Once = ONCE_INIT;
unsafe {
ONCE.call_once(|| {
mach_timebase_info(&mut INFO);
});
&INFO
}
}
pub fn get_time() -> (i64, i32) {
use std::ptr;
let mut tv = timeval { tv_sec: 0, tv_usec: 0 };
unsafe { libc::gettimeofday(&mut tv, ptr::null_mut()); }
(tv.tv_sec as i64, tv.tv_usec * 1000)
}
#[allow(deprecated)]
#[inline]
pub fn get_precise_ns() -> u64 {
unsafe {
let time = libc::mach_absolute_time();
let info = info();
time * info.numer as u64 / info.denom as u64
}
}
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
pub struct SteadyTime { t: u64 }
impl SteadyTime {
pub fn now() -> SteadyTime {
SteadyTime { t: get_precise_ns() }
}
}
impl Sub for SteadyTime {
type Output = Duration;
fn sub(self, other: SteadyTime) -> Duration {
Duration::nanoseconds(self.t as i64 - other.t as i64)
}
}
impl Sub<Duration> for SteadyTime {
type Output = SteadyTime;
fn sub(self, other: Duration) -> SteadyTime {
self + -other
}
}
impl Add<Duration> for SteadyTime {
type Output = SteadyTime;
fn add(self, other: Duration) -> SteadyTime {
let delta = other.num_nanoseconds().unwrap();
SteadyTime {
t: (self.t as i64 + delta) as u64
}
}
}
}
#[cfg(test)]
pub struct TzReset;
#[cfg(test)]
pub fn set_los_angeles_time_zone() -> TzReset {
use std::env;
env::set_var("TZ", "America/Los_Angeles");
::tzset();
TzReset
}
#[cfg(test)]
pub fn set_london_with_dst_time_zone() -> TzReset {
use std::env;
env::set_var("TZ", "Europe/London");
::tzset();
TzReset
}
#[cfg(all(not(target_os = "macos"), not(target_os = "ios")))]
mod unix {
use std::fmt;
use std::cmp::Ordering;
use std::ops::{Add, Sub};
use libc;
use Duration;
pub fn get_time() -> (i64, i32) {
let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); }
(tv.tv_sec as i64, tv.tv_nsec as i32)
}
pub fn get_precise_ns() -> u64 {
let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 };
unsafe {
libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts);
}
(ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64)
}
#[derive(Copy)]
pub struct SteadyTime {
t: libc::timespec,
}
impl fmt::Debug for SteadyTime {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}",
self.t.tv_sec, self.t.tv_nsec)
}
}
impl Clone for SteadyTime {
fn clone(&self) -> SteadyTime {
SteadyTime { t: self.t }
}
}
impl SteadyTime {
pub fn now() -> SteadyTime {
let mut t = SteadyTime {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
}
};
unsafe {
assert_eq!(0, libc::clock_gettime(libc::CLOCK_MONOTONIC,
&mut t.t));
}
t
}
}
impl Sub for SteadyTime {
type Output = Duration;
fn sub(self, other: SteadyTime) -> Duration {
if self.t.tv_nsec >= other.t.tv_nsec {
Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) +
Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64)
} else {
Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) +
Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 -
other.t.tv_nsec as i64)
}
}
}
impl Sub<Duration> for SteadyTime {
type Output = SteadyTime;
fn sub(self, other: Duration) -> SteadyTime {
self + -other
}
}
impl Add<Duration> for SteadyTime {
type Output = SteadyTime;
fn add(mut self, other: Duration) -> SteadyTime {
let seconds = other.num_seconds();
let nanoseconds = other - Duration::seconds(seconds);
let nanoseconds = nanoseconds.num_nanoseconds().unwrap();
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
type nsec = i64;
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
type nsec = libc::c_long;
self.t.tv_sec += seconds as libc::time_t;
self.t.tv_nsec += nanoseconds as nsec;
if self.t.tv_nsec >= ::NSEC_PER_SEC as nsec {
self.t.tv_nsec -= ::NSEC_PER_SEC as nsec;
self.t.tv_sec += 1;
} else if self.t.tv_nsec < 0 {
self.t.tv_sec -= 1;
self.t.tv_nsec += ::NSEC_PER_SEC as nsec;
}
self
}
}
impl PartialOrd for SteadyTime {
fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for SteadyTime {
fn cmp(&self, other: &SteadyTime) -> Ordering {
match self.t.tv_sec.cmp(&other.t.tv_sec) {
Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec),
ord => ord
}
}
}
impl PartialEq for SteadyTime {
fn eq(&self, other: &SteadyTime) -> bool {
self.t.tv_sec == other.t.tv_sec &&
self.t.tv_nsec == other.t.tv_nsec
}
}
impl Eq for SteadyTime {}
}
}
#[cfg(windows)]
#[allow(non_snake_case)]
mod inner {
use std::io;
use std::mem;
#[allow(deprecated)]
use std::sync::{Once, ONCE_INIT};
use std::ops::{Add, Sub};
use {Tm, Duration};
use winapi::um::winnt::*;
use winapi::shared::minwindef::*;
use winapi::um::minwinbase::SYSTEMTIME;
use winapi::um::profileapi::*;
use winapi::um::timezoneapi::*;
use winapi::um::sysinfoapi::GetSystemTimeAsFileTime;
fn frequency() -> i64 {
static mut FREQUENCY: i64 = 0;
#[allow(deprecated)]
static ONCE: Once = ONCE_INIT;
unsafe {
ONCE.call_once(|| {
let mut l = i64_to_large_integer(0);
QueryPerformanceFrequency(&mut l);
FREQUENCY = large_integer_to_i64(l);
});
FREQUENCY
}
}
fn i64_to_large_integer(i: i64) -> LARGE_INTEGER {
unsafe {
let mut large_integer: LARGE_INTEGER = mem::zeroed();
*large_integer.QuadPart_mut() = i;
large_integer
}
}
fn large_integer_to_i64(l: LARGE_INTEGER) -> i64 {
unsafe {
*l.QuadPart()
}
}
const HECTONANOSECS_IN_SEC: i64 = 10_000_000;
const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC;
fn time_to_file_time(sec: i64) -> FILETIME {
let t = (((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH)) as u64;
FILETIME {
dwLowDateTime: t as DWORD,
dwHighDateTime: (t >> 32) as DWORD
}
}
fn file_time_as_u64(ft: &FILETIME) -> u64 {
((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64)
}
fn file_time_to_nsec(ft: &FILETIME) -> i32 {
let t = file_time_as_u64(ft) as i64;
((t % HECTONANOSECS_IN_SEC) * 100) as i32
}
fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 {
let t = file_time_as_u64(ft) as i64;
((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64
}
fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME {
unsafe {
let mut ft = mem::zeroed();
SystemTimeToFileTime(sys, &mut ft);
ft
}
}
fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME {
let mut sys: SYSTEMTIME = unsafe { mem::zeroed() };
sys.wSecond = tm.tm_sec as WORD;
sys.wMinute = tm.tm_min as WORD;
sys.wHour = tm.tm_hour as WORD;
sys.wDay = tm.tm_mday as WORD;
sys.wDayOfWeek = tm.tm_wday as WORD;
sys.wMonth = (tm.tm_mon + 1) as WORD;
sys.wYear = (tm.tm_year + 1900) as WORD;
sys
}
fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) {
tm.tm_sec = sys.wSecond as i32;
tm.tm_min = sys.wMinute as i32;
tm.tm_hour = sys.wHour as i32;
tm.tm_mday = sys.wDay as i32;
tm.tm_wday = sys.wDayOfWeek as i32;
tm.tm_mon = (sys.wMonth - 1) as i32;
tm.tm_year = (sys.wYear - 1900) as i32;
tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday);
fn yday(year: i32, month: i32, day: i32) -> i32 {
let leap = if month > 2 {
if year % 4 == 0 { 1 } else { 2 }
} else {
0
};
let july = if month > 7 { 1 } else { 0 };
(month - 1) * 30 + month / 2 + (day - 1) - leap + july
}
}
macro_rules! call {
($name:ident($($arg:expr),*)) => {
if $name($($arg),*) == 0 {
panic!(concat!(stringify!($name), " failed with: {}"),
io::Error::last_os_error());
}
}
}
pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
let mut out = unsafe { mem::zeroed() };
let ft = time_to_file_time(sec);
unsafe {
call!(FileTimeToSystemTime(&ft, &mut out));
}
system_time_to_tm(&out, tm);
tm.tm_utcoff = 0;
}
pub fn time_to_local_tm(sec: i64, tm: &mut Tm) {
let ft = time_to_file_time(sec);
unsafe {
let mut utc = mem::zeroed();
let mut local = mem::zeroed();
call!(FileTimeToSystemTime(&ft, &mut utc));
call!(SystemTimeToTzSpecificLocalTime(0 as *const _,
&mut utc, &mut local));
system_time_to_tm(&local, tm);
let local = system_time_to_file_time(&local);
let local_sec = file_time_to_unix_seconds(&local);
let mut tz = mem::zeroed();
GetTimeZoneInformation(&mut tz);
// SystemTimeToTzSpecificLocalTime already applied the biases so
// check if it non standard
tm.tm_utcoff = (local_sec - sec) as i32;
tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) {
0
} else {
1
};
}
}
pub fn utc_tm_to_time(tm: &Tm) -> i64 {
unsafe {
let mut ft = mem::zeroed();
let sys_time = tm_to_system_time(tm);
call!(SystemTimeToFileTime(&sys_time, &mut ft));
file_time_to_unix_seconds(&ft)
}
}
pub fn local_tm_to_time(tm: &Tm) -> i64 {
unsafe {
let mut ft = mem::zeroed();
let mut utc = mem::zeroed();
let mut sys_time = tm_to_system_time(tm);
call!(TzSpecificLocalTimeToSystemTime(0 as *mut _,
&mut sys_time, &mut utc));
call!(SystemTimeToFileTime(&utc, &mut ft));
file_time_to_unix_seconds(&ft)
}
}
pub fn get_time() -> (i64, i32) {
unsafe {
let mut ft = mem::zeroed();
GetSystemTimeAsFileTime(&mut ft);
(file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft))
}
}
pub fn get_precise_ns() -> u64 {
let mut ticks = i64_to_large_integer(0);
unsafe {
assert!(QueryPerformanceCounter(&mut ticks) == 1);
}
mul_div_i64(large_integer_to_i64(ticks), 1000000000, frequency()) as u64
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct SteadyTime {
t: i64,
}
impl SteadyTime {
pub fn now() -> SteadyTime {
let mut l = i64_to_large_integer(0);
unsafe { QueryPerformanceCounter(&mut l); }
SteadyTime { t : large_integer_to_i64(l) }
}
}
impl Sub for SteadyTime {
type Output = Duration;
fn sub(self, other: SteadyTime) -> Duration {
let diff = self.t as i64 - other.t as i64;
Duration::nanoseconds(mul_div_i64(diff, 1000000000,
frequency()))
}
}
impl Sub<Duration> for SteadyTime {
type Output = SteadyTime;
fn sub(self, other: Duration) -> SteadyTime {
self + -other
}
}
impl Add<Duration> for SteadyTime {
type Output = SteadyTime;
fn add(mut self, other: Duration) -> SteadyTime {
self.t += (other.num_microseconds().unwrap() * frequency() /
1_000_000) as i64;
self
}
}
#[cfg(test)]
pub struct TzReset {
old: TIME_ZONE_INFORMATION,
}
#[cfg(test)]
impl Drop for TzReset {
fn drop(&mut self) {
unsafe {
call!(SetTimeZoneInformation(&self.old));
}
}
}
#[cfg(test)]
pub fn set_los_angeles_time_zone() -> TzReset {
acquire_privileges();
unsafe {
let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>();
GetTimeZoneInformation(&mut tz);
let ret = TzReset { old: tz };
tz.Bias = 60 * 8;
call!(SetTimeZoneInformation(&tz));
return ret
}
}
#[cfg(test)]
pub fn set_london_with_dst_time_zone() -> TzReset {
acquire_privileges();
unsafe {
let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>();
GetTimeZoneInformation(&mut tz);
let ret = TzReset { old: tz };
// Since date set precisely this is 2015's dates
tz.Bias = 0;
tz.DaylightBias = -60;
tz.DaylightDate.wYear = 0;
tz.DaylightDate.wMonth = 3;
tz.DaylightDate.wDayOfWeek = 0;
tz.DaylightDate.wDay = 5;
tz.DaylightDate.wHour = 2;
tz.StandardBias = 0;
tz.StandardDate.wYear = 0;
tz.StandardDate.wMonth = 10;
tz.StandardDate.wDayOfWeek = 0;
tz.StandardDate.wDay = 5;
tz.StandardDate.wHour = 2;
call!(SetTimeZoneInformation(&tz));
return ret
}
}
// Ensures that this process has the necessary privileges to set a new time
// zone, and this is all transcribed from:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724944%28v=vs.85%29.aspx
#[cfg(test)]
fn acquire_privileges() {
use winapi::um::processthreadsapi::*;
use winapi::um::winbase::LookupPrivilegeValueA;
const SE_PRIVILEGE_ENABLED: DWORD = 2;
#[allow(deprecated)]
static INIT: Once = ONCE_INIT;
// TODO: FIXME
extern "system" {
fn AdjustTokenPrivileges(
TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES,
BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD,
) -> BOOL;
}
INIT.call_once(|| unsafe {
let mut hToken = 0 as *mut _;
call!(OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&mut hToken));
let mut tkp = mem::zeroed::<TOKEN_PRIVILEGES>();
assert_eq!(tkp.Privileges.len(), 1);
let c = ::std::ffi::CString::new("SeTimeZonePrivilege").unwrap();
call!(LookupPrivilegeValueA(0 as *const _, c.as_ptr(),
&mut tkp.Privileges[0].Luid));
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
tkp.PrivilegeCount = 1;
call!(AdjustTokenPrivileges(hToken, FALSE, &mut tkp, 0,
0 as *mut _, 0 as *mut _));
});
}
// Computes (value*numer)/denom without overflow, as long as both
// (numer*denom) and the overall result fit into i64 (which is the case
// for our time conversions).
fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 {
let q = value / denom;
let r = value % denom;
// Decompose value as (value/denom*denom + value%denom),
// substitute into (value*numer)/denom and simplify.
// r < denom, so (denom*numer) is the upper bound of (r*numer)
q * numer + r * numer / denom
}
#[test]
fn test_muldiv() {
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000),
1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000),
-1_000_000_000_001_000);
assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000),
1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000),
-1_000_000_000_001_000);
assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000),
1_000_000_000_001_000);
}
}