summaryrefslogtreecommitdiffstats
path: root/third_party/rust/time-0.1.45/src/sys.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/time-0.1.45/src/sys.rs')
-rw-r--r--third_party/rust/time-0.1.45/src/sys.rs996
1 files changed, 996 insertions, 0 deletions
diff --git a/third_party/rust/time-0.1.45/src/sys.rs b/third_party/rust/time-0.1.45/src/sys.rs
new file mode 100644
index 0000000000..c5765ca895
--- /dev/null
+++ b/third_party/rust/time-0.1.45/src/sys.rs
@@ -0,0 +1,996 @@
+#![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(any(target_os = "emscripten", target_os = "wasi"))))]
+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_os = "wasi")]
+mod inner {
+ use std::ops::{Add, Sub};
+ use Tm;
+ use Duration;
+ use super::common::{time_to_tm, tm_to_time};
+ use wasi::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME};
+
+ #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+ pub struct SteadyTime {
+ t: u64
+ }
+
+ 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) {
+ let ts = get_precise_ns();
+ (
+ ts as i64 / 1_000_000_000,
+ (ts as i64 % 1_000_000_000) as i32,
+ )
+ }
+
+ pub fn get_precise_ns() -> u64 {
+ unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000_000) }
+ .expect("Host doesn't implement a real-time clock")
+ }
+
+ impl SteadyTime {
+ pub fn now() -> SteadyTime {
+ SteadyTime {
+ t: unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000_000) }
+ .expect("Host doesn't implement a monotonic clock"),
+ }
+ }
+ }
+
+ 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(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::mem::zeroed;
+ use std::ops::{Add, Sub};
+ use libc;
+
+ use Duration;
+
+ pub fn get_time() -> (i64, i32) {
+ // SAFETY: libc::timespec is zero initializable.
+ let mut tv: libc::timespec = unsafe { zeroed() };
+ 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 {
+ // SAFETY: libc::timespec is zero initializable.
+ let mut ts: libc::timespec = unsafe { zeroed() };
+ 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 {
+ // SAFETY: libc::timespec is zero initializable.
+ t: unsafe { zeroed() }
+ };
+ 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);
+ }
+}