1 #![allow(bad_style)] 2 3 pub use self::inner::*; 4 5 #[cfg(any( 6 all(target_arch = "wasm32", not(target_os = "emscripten")), 7 target_env = "sgx" 8 ))] 9 mod common { 10 use Tm; 11 time_to_tm(ts: i64, tm: &mut Tm)12 pub fn time_to_tm(ts: i64, tm: &mut Tm) { 13 let leapyear = |year| -> bool { 14 year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) 15 }; 16 17 static _ytab: [[i64; 12]; 2] = [ 18 [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], 19 [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] 20 ]; 21 22 let mut year = 1970; 23 24 let dayclock = ts % 86400; 25 let mut dayno = ts / 86400; 26 27 tm.tm_sec = (dayclock % 60) as i32; 28 tm.tm_min = ((dayclock % 3600) / 60) as i32; 29 tm.tm_hour = (dayclock / 3600) as i32; 30 tm.tm_wday = ((dayno + 4) % 7) as i32; 31 loop { 32 let yearsize = if leapyear(year) { 33 366 34 } else { 35 365 36 }; 37 if dayno >= yearsize { 38 dayno -= yearsize; 39 year += 1; 40 } else { 41 break; 42 } 43 } 44 tm.tm_year = (year - 1900) as i32; 45 tm.tm_yday = dayno as i32; 46 let mut mon = 0; 47 while dayno >= _ytab[if leapyear(year) { 1 } else { 0 }][mon] { 48 dayno -= _ytab[if leapyear(year) { 1 } else { 0 }][mon]; 49 mon += 1; 50 } 51 tm.tm_mon = mon as i32; 52 tm.tm_mday = dayno as i32 + 1; 53 tm.tm_isdst = 0; 54 } 55 tm_to_time(tm: &Tm) -> i6456 pub fn tm_to_time(tm: &Tm) -> i64 { 57 let mut y = tm.tm_year as i64 + 1900; 58 let mut m = tm.tm_mon as i64 + 1; 59 if m <= 2 { 60 y -= 1; 61 m += 12; 62 } 63 let d = tm.tm_mday as i64; 64 let h = tm.tm_hour as i64; 65 let mi = tm.tm_min as i64; 66 let s = tm.tm_sec as i64; 67 (365*y + y/4 - y/100 + y/400 + 3*(m+1)/5 + 30*m + d - 719561) 68 * 86400 + 3600 * h + 60 * mi + s 69 } 70 } 71 72 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] 73 mod inner { 74 use std::ops::{Add, Sub}; 75 use Tm; 76 use Duration; 77 use super::common::{time_to_tm, tm_to_time}; 78 79 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 80 pub struct SteadyTime; 81 time_to_utc_tm(sec: i64, tm: &mut Tm)82 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 83 time_to_tm(sec, tm); 84 } 85 time_to_local_tm(sec: i64, tm: &mut Tm)86 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 87 // FIXME: Add timezone logic 88 time_to_tm(sec, tm); 89 } 90 utc_tm_to_time(tm: &Tm) -> i6491 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 92 tm_to_time(tm) 93 } 94 local_tm_to_time(tm: &Tm) -> i6495 pub fn local_tm_to_time(tm: &Tm) -> i64 { 96 // FIXME: Add timezone logic 97 tm_to_time(tm) 98 } 99 get_time() -> (i64, i32)100 pub fn get_time() -> (i64, i32) { 101 unimplemented!() 102 } 103 get_precise_ns() -> u64104 pub fn get_precise_ns() -> u64 { 105 unimplemented!() 106 } 107 108 impl SteadyTime { now() -> SteadyTime109 pub fn now() -> SteadyTime { 110 unimplemented!() 111 } 112 } 113 114 impl Sub for SteadyTime { 115 type Output = Duration; sub(self, _other: SteadyTime) -> Duration116 fn sub(self, _other: SteadyTime) -> Duration { 117 unimplemented!() 118 } 119 } 120 121 impl Sub<Duration> for SteadyTime { 122 type Output = SteadyTime; sub(self, _other: Duration) -> SteadyTime123 fn sub(self, _other: Duration) -> SteadyTime { 124 unimplemented!() 125 } 126 } 127 128 impl Add<Duration> for SteadyTime { 129 type Output = SteadyTime; add(self, _other: Duration) -> SteadyTime130 fn add(self, _other: Duration) -> SteadyTime { 131 unimplemented!() 132 } 133 } 134 } 135 136 #[cfg(target_env = "sgx")] 137 mod inner { 138 use std::ops::{Add, Sub}; 139 use Tm; 140 use Duration; 141 use super::common::{time_to_tm, tm_to_time}; 142 use std::time::SystemTime; 143 144 /// The number of nanoseconds in seconds. 145 const NANOS_PER_SEC: u64 = 1_000_000_000; 146 147 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 148 pub struct SteadyTime { 149 t: Duration 150 } 151 time_to_utc_tm(sec: i64, tm: &mut Tm)152 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 153 time_to_tm(sec, tm); 154 } 155 time_to_local_tm(sec: i64, tm: &mut Tm)156 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 157 // FIXME: Add timezone logic 158 time_to_tm(sec, tm); 159 } 160 utc_tm_to_time(tm: &Tm) -> i64161 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 162 tm_to_time(tm) 163 } 164 local_tm_to_time(tm: &Tm) -> i64165 pub fn local_tm_to_time(tm: &Tm) -> i64 { 166 // FIXME: Add timezone logic 167 tm_to_time(tm) 168 } 169 get_time() -> (i64, i32)170 pub fn get_time() -> (i64, i32) { 171 SteadyTime::now().t.raw() 172 } 173 get_precise_ns() -> u64174 pub fn get_precise_ns() -> u64 { 175 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system 176 // clock is adjusted backward. 177 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 178 std_duration.as_secs() * NANOS_PER_SEC + std_duration.subsec_nanos() as u64 179 } 180 181 impl SteadyTime { now() -> SteadyTime182 pub fn now() -> SteadyTime { 183 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system 184 // clock is adjusted backward. 185 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 186 // This unwrap is safe because duration is well within the limits of i64. 187 let duration = Duration::from_std(std_duration).unwrap(); 188 SteadyTime { t: duration } 189 } 190 } 191 192 impl Sub for SteadyTime { 193 type Output = Duration; sub(self, other: SteadyTime) -> Duration194 fn sub(self, other: SteadyTime) -> Duration { 195 self.t - other.t 196 } 197 } 198 199 impl Sub<Duration> for SteadyTime { 200 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime201 fn sub(self, other: Duration) -> SteadyTime { 202 SteadyTime { t: self.t - other } 203 } 204 } 205 206 impl Add<Duration> for SteadyTime { 207 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime208 fn add(self, other: Duration) -> SteadyTime { 209 SteadyTime { t: self.t + other } 210 } 211 } 212 } 213 214 #[cfg(unix)] 215 mod inner { 216 use libc::{self, time_t}; 217 use std::mem; 218 use std::io; 219 use Tm; 220 221 #[cfg(any(target_os = "macos", target_os = "ios"))] 222 pub use self::mac::*; 223 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 224 pub use self::unix::*; 225 226 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 227 extern { 228 static timezone: time_t; 229 static altzone: time_t; 230 } 231 rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm)232 fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) { 233 tm.tm_sec = rust_tm.tm_sec; 234 tm.tm_min = rust_tm.tm_min; 235 tm.tm_hour = rust_tm.tm_hour; 236 tm.tm_mday = rust_tm.tm_mday; 237 tm.tm_mon = rust_tm.tm_mon; 238 tm.tm_year = rust_tm.tm_year; 239 tm.tm_wday = rust_tm.tm_wday; 240 tm.tm_yday = rust_tm.tm_yday; 241 tm.tm_isdst = rust_tm.tm_isdst; 242 } 243 tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm)244 fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) { 245 rust_tm.tm_sec = tm.tm_sec; 246 rust_tm.tm_min = tm.tm_min; 247 rust_tm.tm_hour = tm.tm_hour; 248 rust_tm.tm_mday = tm.tm_mday; 249 rust_tm.tm_mon = tm.tm_mon; 250 rust_tm.tm_year = tm.tm_year; 251 rust_tm.tm_wday = tm.tm_wday; 252 rust_tm.tm_yday = tm.tm_yday; 253 rust_tm.tm_isdst = tm.tm_isdst; 254 rust_tm.tm_utcoff = utcoff; 255 } 256 257 #[cfg(any(target_os = "nacl", target_os = "solaris", target_os = "illumos"))] timegm(tm: *mut libc::tm) -> time_t258 unsafe fn timegm(tm: *mut libc::tm) -> time_t { 259 use std::env::{set_var, var_os, remove_var}; 260 extern { 261 fn tzset(); 262 } 263 264 let ret; 265 266 let current_tz = var_os("TZ"); 267 set_var("TZ", "UTC"); 268 tzset(); 269 270 ret = libc::mktime(tm); 271 272 if let Some(tz) = current_tz { 273 set_var("TZ", tz); 274 } else { 275 remove_var("TZ"); 276 } 277 tzset(); 278 279 ret 280 } 281 time_to_utc_tm(sec: i64, tm: &mut Tm)282 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 283 unsafe { 284 let sec = sec as time_t; 285 let mut out = mem::zeroed(); 286 if libc::gmtime_r(&sec, &mut out).is_null() { 287 panic!("gmtime_r failed: {}", io::Error::last_os_error()); 288 } 289 tm_to_rust_tm(&out, 0, tm); 290 } 291 } 292 time_to_local_tm(sec: i64, tm: &mut Tm)293 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 294 unsafe { 295 let sec = sec as time_t; 296 let mut out = mem::zeroed(); 297 if libc::localtime_r(&sec, &mut out).is_null() { 298 panic!("localtime_r failed: {}", io::Error::last_os_error()); 299 } 300 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 301 let gmtoff = { 302 ::tzset(); 303 // < 0 means we don't know; assume we're not in DST. 304 if out.tm_isdst == 0 { 305 // timezone is seconds west of UTC, tm_gmtoff is seconds east 306 -timezone 307 } else if out.tm_isdst > 0 { 308 -altzone 309 } else { 310 -timezone 311 } 312 }; 313 #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] 314 let gmtoff = out.tm_gmtoff; 315 tm_to_rust_tm(&out, gmtoff as i32, tm); 316 } 317 } 318 utc_tm_to_time(rust_tm: &Tm) -> i64319 pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 { 320 #[cfg(all(target_os = "android", target_pointer_width = "32"))] 321 use libc::timegm64 as timegm; 322 #[cfg(not(any( 323 all(target_os = "android", target_pointer_width = "32"), 324 target_os = "nacl", 325 target_os = "solaris", 326 target_os = "illumos" 327 )))] 328 use libc::timegm; 329 330 let mut tm = unsafe { mem::zeroed() }; 331 rust_tm_to_tm(rust_tm, &mut tm); 332 unsafe { timegm(&mut tm) as i64 } 333 } 334 local_tm_to_time(rust_tm: &Tm) -> i64335 pub fn local_tm_to_time(rust_tm: &Tm) -> i64 { 336 let mut tm = unsafe { mem::zeroed() }; 337 rust_tm_to_tm(rust_tm, &mut tm); 338 unsafe { libc::mktime(&mut tm) as i64 } 339 } 340 341 #[cfg(any(target_os = "macos", target_os = "ios"))] 342 mod mac { 343 #[allow(deprecated)] 344 use libc::{self, timeval, mach_timebase_info}; 345 #[allow(deprecated)] 346 use std::sync::{Once, ONCE_INIT}; 347 use std::ops::{Add, Sub}; 348 use Duration; 349 350 #[allow(deprecated)] info() -> &'static mach_timebase_info351 fn info() -> &'static mach_timebase_info { 352 static mut INFO: mach_timebase_info = mach_timebase_info { 353 numer: 0, 354 denom: 0, 355 }; 356 static ONCE: Once = ONCE_INIT; 357 358 unsafe { 359 ONCE.call_once(|| { 360 mach_timebase_info(&mut INFO); 361 }); 362 &INFO 363 } 364 } 365 get_time() -> (i64, i32)366 pub fn get_time() -> (i64, i32) { 367 use std::ptr; 368 let mut tv = timeval { tv_sec: 0, tv_usec: 0 }; 369 unsafe { libc::gettimeofday(&mut tv, ptr::null_mut()); } 370 (tv.tv_sec as i64, tv.tv_usec * 1000) 371 } 372 373 #[allow(deprecated)] 374 #[inline] get_precise_ns() -> u64375 pub fn get_precise_ns() -> u64 { 376 unsafe { 377 let time = libc::mach_absolute_time(); 378 let info = info(); 379 time * info.numer as u64 / info.denom as u64 380 } 381 } 382 383 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] 384 pub struct SteadyTime { t: u64 } 385 386 impl SteadyTime { now() -> SteadyTime387 pub fn now() -> SteadyTime { 388 SteadyTime { t: get_precise_ns() } 389 } 390 } 391 impl Sub for SteadyTime { 392 type Output = Duration; sub(self, other: SteadyTime) -> Duration393 fn sub(self, other: SteadyTime) -> Duration { 394 Duration::nanoseconds(self.t as i64 - other.t as i64) 395 } 396 } 397 impl Sub<Duration> for SteadyTime { 398 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime399 fn sub(self, other: Duration) -> SteadyTime { 400 self + -other 401 } 402 } 403 impl Add<Duration> for SteadyTime { 404 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime405 fn add(self, other: Duration) -> SteadyTime { 406 let delta = other.num_nanoseconds().unwrap(); 407 SteadyTime { 408 t: (self.t as i64 + delta) as u64 409 } 410 } 411 } 412 } 413 414 #[cfg(test)] 415 pub struct TzReset; 416 417 #[cfg(test)] set_los_angeles_time_zone() -> TzReset418 pub fn set_los_angeles_time_zone() -> TzReset { 419 use std::env; 420 env::set_var("TZ", "America/Los_Angeles"); 421 ::tzset(); 422 TzReset 423 } 424 425 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset426 pub fn set_london_with_dst_time_zone() -> TzReset { 427 use std::env; 428 env::set_var("TZ", "Europe/London"); 429 ::tzset(); 430 TzReset 431 } 432 433 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 434 mod unix { 435 use std::fmt; 436 use std::cmp::Ordering; 437 use std::ops::{Add, Sub}; 438 use libc; 439 440 use Duration; 441 get_time() -> (i64, i32)442 pub fn get_time() -> (i64, i32) { 443 let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 444 unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); } 445 (tv.tv_sec as i64, tv.tv_nsec as i32) 446 } 447 get_precise_ns() -> u64448 pub fn get_precise_ns() -> u64 { 449 let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 450 unsafe { 451 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); 452 } 453 (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) 454 } 455 456 #[derive(Copy)] 457 pub struct SteadyTime { 458 t: libc::timespec, 459 } 460 461 impl fmt::Debug for SteadyTime { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result462 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 463 write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", 464 self.t.tv_sec, self.t.tv_nsec) 465 } 466 } 467 468 impl Clone for SteadyTime { clone(&self) -> SteadyTime469 fn clone(&self) -> SteadyTime { 470 SteadyTime { t: self.t } 471 } 472 } 473 474 impl SteadyTime { now() -> SteadyTime475 pub fn now() -> SteadyTime { 476 let mut t = SteadyTime { 477 t: libc::timespec { 478 tv_sec: 0, 479 tv_nsec: 0, 480 } 481 }; 482 unsafe { 483 assert_eq!(0, libc::clock_gettime(libc::CLOCK_MONOTONIC, 484 &mut t.t)); 485 } 486 t 487 } 488 } 489 490 impl Sub for SteadyTime { 491 type Output = Duration; sub(self, other: SteadyTime) -> Duration492 fn sub(self, other: SteadyTime) -> Duration { 493 if self.t.tv_nsec >= other.t.tv_nsec { 494 Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + 495 Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) 496 } else { 497 Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + 498 Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - 499 other.t.tv_nsec as i64) 500 } 501 } 502 } 503 504 impl Sub<Duration> for SteadyTime { 505 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime506 fn sub(self, other: Duration) -> SteadyTime { 507 self + -other 508 } 509 } 510 511 impl Add<Duration> for SteadyTime { 512 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime513 fn add(mut self, other: Duration) -> SteadyTime { 514 let seconds = other.num_seconds(); 515 let nanoseconds = other - Duration::seconds(seconds); 516 let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); 517 518 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] 519 type nsec = i64; 520 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] 521 type nsec = libc::c_long; 522 523 self.t.tv_sec += seconds as libc::time_t; 524 self.t.tv_nsec += nanoseconds as nsec; 525 if self.t.tv_nsec >= ::NSEC_PER_SEC as nsec { 526 self.t.tv_nsec -= ::NSEC_PER_SEC as nsec; 527 self.t.tv_sec += 1; 528 } else if self.t.tv_nsec < 0 { 529 self.t.tv_sec -= 1; 530 self.t.tv_nsec += ::NSEC_PER_SEC as nsec; 531 } 532 self 533 } 534 } 535 536 impl PartialOrd for SteadyTime { partial_cmp(&self, other: &SteadyTime) -> Option<Ordering>537 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { 538 Some(self.cmp(other)) 539 } 540 } 541 542 impl Ord for SteadyTime { cmp(&self, other: &SteadyTime) -> Ordering543 fn cmp(&self, other: &SteadyTime) -> Ordering { 544 match self.t.tv_sec.cmp(&other.t.tv_sec) { 545 Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), 546 ord => ord 547 } 548 } 549 } 550 551 impl PartialEq for SteadyTime { eq(&self, other: &SteadyTime) -> bool552 fn eq(&self, other: &SteadyTime) -> bool { 553 self.t.tv_sec == other.t.tv_sec && 554 self.t.tv_nsec == other.t.tv_nsec 555 } 556 } 557 558 impl Eq for SteadyTime {} 559 560 } 561 } 562 563 #[cfg(windows)] 564 #[allow(non_snake_case)] 565 mod inner { 566 use std::io; 567 use std::mem; 568 #[allow(deprecated)] 569 use std::sync::{Once, ONCE_INIT}; 570 use std::ops::{Add, Sub}; 571 use {Tm, Duration}; 572 573 use winapi::um::winnt::*; 574 use winapi::shared::minwindef::*; 575 use winapi::um::minwinbase::SYSTEMTIME; 576 use winapi::um::profileapi::*; 577 use winapi::um::timezoneapi::*; 578 use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; 579 frequency() -> i64580 fn frequency() -> i64 { 581 static mut FREQUENCY: i64 = 0; 582 #[allow(deprecated)] 583 static ONCE: Once = ONCE_INIT; 584 585 unsafe { 586 ONCE.call_once(|| { 587 let mut l = i64_to_large_integer(0); 588 QueryPerformanceFrequency(&mut l); 589 FREQUENCY = large_integer_to_i64(l); 590 }); 591 FREQUENCY 592 } 593 } 594 i64_to_large_integer(i: i64) -> LARGE_INTEGER595 fn i64_to_large_integer(i: i64) -> LARGE_INTEGER { 596 unsafe { 597 let mut large_integer: LARGE_INTEGER = mem::zeroed(); 598 *large_integer.QuadPart_mut() = i; 599 large_integer 600 } 601 } 602 large_integer_to_i64(l: LARGE_INTEGER) -> i64603 fn large_integer_to_i64(l: LARGE_INTEGER) -> i64 { 604 unsafe { 605 *l.QuadPart() 606 } 607 } 608 609 const HECTONANOSECS_IN_SEC: i64 = 10_000_000; 610 const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; 611 time_to_file_time(sec: i64) -> FILETIME612 fn time_to_file_time(sec: i64) -> FILETIME { 613 let t = (((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH)) as u64; 614 FILETIME { 615 dwLowDateTime: t as DWORD, 616 dwHighDateTime: (t >> 32) as DWORD 617 } 618 } 619 file_time_as_u64(ft: &FILETIME) -> u64620 fn file_time_as_u64(ft: &FILETIME) -> u64 { 621 ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) 622 } 623 file_time_to_nsec(ft: &FILETIME) -> i32624 fn file_time_to_nsec(ft: &FILETIME) -> i32 { 625 let t = file_time_as_u64(ft) as i64; 626 ((t % HECTONANOSECS_IN_SEC) * 100) as i32 627 } 628 file_time_to_unix_seconds(ft: &FILETIME) -> i64629 fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { 630 let t = file_time_as_u64(ft) as i64; 631 ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 632 } 633 system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME634 fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { 635 unsafe { 636 let mut ft = mem::zeroed(); 637 SystemTimeToFileTime(sys, &mut ft); 638 ft 639 } 640 } 641 tm_to_system_time(tm: &Tm) -> SYSTEMTIME642 fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { 643 let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; 644 sys.wSecond = tm.tm_sec as WORD; 645 sys.wMinute = tm.tm_min as WORD; 646 sys.wHour = tm.tm_hour as WORD; 647 sys.wDay = tm.tm_mday as WORD; 648 sys.wDayOfWeek = tm.tm_wday as WORD; 649 sys.wMonth = (tm.tm_mon + 1) as WORD; 650 sys.wYear = (tm.tm_year + 1900) as WORD; 651 sys 652 } 653 system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm)654 fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { 655 tm.tm_sec = sys.wSecond as i32; 656 tm.tm_min = sys.wMinute as i32; 657 tm.tm_hour = sys.wHour as i32; 658 tm.tm_mday = sys.wDay as i32; 659 tm.tm_wday = sys.wDayOfWeek as i32; 660 tm.tm_mon = (sys.wMonth - 1) as i32; 661 tm.tm_year = (sys.wYear - 1900) as i32; 662 tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); 663 664 fn yday(year: i32, month: i32, day: i32) -> i32 { 665 let leap = if month > 2 { 666 if year % 4 == 0 { 1 } else { 2 } 667 } else { 668 0 669 }; 670 let july = if month > 7 { 1 } else { 0 }; 671 672 (month - 1) * 30 + month / 2 + (day - 1) - leap + july 673 } 674 } 675 676 macro_rules! call { 677 ($name:ident($($arg:expr),*)) => { 678 if $name($($arg),*) == 0 { 679 panic!(concat!(stringify!($name), " failed with: {}"), 680 io::Error::last_os_error()); 681 } 682 } 683 } 684 time_to_utc_tm(sec: i64, tm: &mut Tm)685 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 686 let mut out = unsafe { mem::zeroed() }; 687 let ft = time_to_file_time(sec); 688 unsafe { 689 call!(FileTimeToSystemTime(&ft, &mut out)); 690 } 691 system_time_to_tm(&out, tm); 692 tm.tm_utcoff = 0; 693 } 694 time_to_local_tm(sec: i64, tm: &mut Tm)695 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 696 let ft = time_to_file_time(sec); 697 unsafe { 698 let mut utc = mem::zeroed(); 699 let mut local = mem::zeroed(); 700 call!(FileTimeToSystemTime(&ft, &mut utc)); 701 call!(SystemTimeToTzSpecificLocalTime(0 as *const _, 702 &mut utc, &mut local)); 703 system_time_to_tm(&local, tm); 704 705 let local = system_time_to_file_time(&local); 706 let local_sec = file_time_to_unix_seconds(&local); 707 708 let mut tz = mem::zeroed(); 709 GetTimeZoneInformation(&mut tz); 710 711 // SystemTimeToTzSpecificLocalTime already applied the biases so 712 // check if it non standard 713 tm.tm_utcoff = (local_sec - sec) as i32; 714 tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 715 0 716 } else { 717 1 718 }; 719 } 720 } 721 utc_tm_to_time(tm: &Tm) -> i64722 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 723 unsafe { 724 let mut ft = mem::zeroed(); 725 let sys_time = tm_to_system_time(tm); 726 call!(SystemTimeToFileTime(&sys_time, &mut ft)); 727 file_time_to_unix_seconds(&ft) 728 } 729 } 730 local_tm_to_time(tm: &Tm) -> i64731 pub fn local_tm_to_time(tm: &Tm) -> i64 { 732 unsafe { 733 let mut ft = mem::zeroed(); 734 let mut utc = mem::zeroed(); 735 let mut sys_time = tm_to_system_time(tm); 736 call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, 737 &mut sys_time, &mut utc)); 738 call!(SystemTimeToFileTime(&utc, &mut ft)); 739 file_time_to_unix_seconds(&ft) 740 } 741 } 742 get_time() -> (i64, i32)743 pub fn get_time() -> (i64, i32) { 744 unsafe { 745 let mut ft = mem::zeroed(); 746 GetSystemTimeAsFileTime(&mut ft); 747 (file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft)) 748 } 749 } 750 get_precise_ns() -> u64751 pub fn get_precise_ns() -> u64 { 752 let mut ticks = i64_to_large_integer(0); 753 unsafe { 754 assert!(QueryPerformanceCounter(&mut ticks) == 1); 755 } 756 mul_div_i64(large_integer_to_i64(ticks), 1000000000, frequency()) as u64 757 758 } 759 760 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] 761 pub struct SteadyTime { 762 t: i64, 763 } 764 765 impl SteadyTime { now() -> SteadyTime766 pub fn now() -> SteadyTime { 767 let mut l = i64_to_large_integer(0); 768 unsafe { QueryPerformanceCounter(&mut l); } 769 SteadyTime { t : large_integer_to_i64(l) } 770 } 771 } 772 773 impl Sub for SteadyTime { 774 type Output = Duration; sub(self, other: SteadyTime) -> Duration775 fn sub(self, other: SteadyTime) -> Duration { 776 let diff = self.t as i64 - other.t as i64; 777 Duration::nanoseconds(mul_div_i64(diff, 1000000000, 778 frequency())) 779 } 780 } 781 782 impl Sub<Duration> for SteadyTime { 783 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime784 fn sub(self, other: Duration) -> SteadyTime { 785 self + -other 786 } 787 } 788 789 impl Add<Duration> for SteadyTime { 790 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime791 fn add(mut self, other: Duration) -> SteadyTime { 792 self.t += (other.num_microseconds().unwrap() * frequency() / 793 1_000_000) as i64; 794 self 795 } 796 } 797 798 #[cfg(test)] 799 pub struct TzReset { 800 old: TIME_ZONE_INFORMATION, 801 } 802 803 #[cfg(test)] 804 impl Drop for TzReset { drop(&mut self)805 fn drop(&mut self) { 806 unsafe { 807 call!(SetTimeZoneInformation(&self.old)); 808 } 809 } 810 } 811 812 #[cfg(test)] set_los_angeles_time_zone() -> TzReset813 pub fn set_los_angeles_time_zone() -> TzReset { 814 acquire_privileges(); 815 816 unsafe { 817 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 818 GetTimeZoneInformation(&mut tz); 819 let ret = TzReset { old: tz }; 820 tz.Bias = 60 * 8; 821 call!(SetTimeZoneInformation(&tz)); 822 return ret 823 } 824 } 825 826 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset827 pub fn set_london_with_dst_time_zone() -> TzReset { 828 acquire_privileges(); 829 830 unsafe { 831 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 832 GetTimeZoneInformation(&mut tz); 833 let ret = TzReset { old: tz }; 834 // Since date set precisely this is 2015's dates 835 tz.Bias = 0; 836 tz.DaylightBias = -60; 837 tz.DaylightDate.wYear = 0; 838 tz.DaylightDate.wMonth = 3; 839 tz.DaylightDate.wDayOfWeek = 0; 840 tz.DaylightDate.wDay = 5; 841 tz.DaylightDate.wHour = 2; 842 tz.StandardBias = 0; 843 tz.StandardDate.wYear = 0; 844 tz.StandardDate.wMonth = 10; 845 tz.StandardDate.wDayOfWeek = 0; 846 tz.StandardDate.wDay = 5; 847 tz.StandardDate.wHour = 2; 848 call!(SetTimeZoneInformation(&tz)); 849 return ret 850 } 851 } 852 853 // Ensures that this process has the necessary privileges to set a new time 854 // zone, and this is all transcribed from: 855 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724944%28v=vs.85%29.aspx 856 #[cfg(test)] acquire_privileges()857 fn acquire_privileges() { 858 use winapi::um::processthreadsapi::*; 859 use winapi::um::winbase::LookupPrivilegeValueA; 860 const SE_PRIVILEGE_ENABLED: DWORD = 2; 861 #[allow(deprecated)] 862 static INIT: Once = ONCE_INIT; 863 864 // TODO: FIXME 865 extern "system" { 866 fn AdjustTokenPrivileges( 867 TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES, 868 BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD, 869 ) -> BOOL; 870 } 871 872 INIT.call_once(|| unsafe { 873 let mut hToken = 0 as *mut _; 874 call!(OpenProcessToken(GetCurrentProcess(), 875 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 876 &mut hToken)); 877 878 let mut tkp = mem::zeroed::<TOKEN_PRIVILEGES>(); 879 assert_eq!(tkp.Privileges.len(), 1); 880 let c = ::std::ffi::CString::new("SeTimeZonePrivilege").unwrap(); 881 call!(LookupPrivilegeValueA(0 as *const _, c.as_ptr(), 882 &mut tkp.Privileges[0].Luid)); 883 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 884 tkp.PrivilegeCount = 1; 885 call!(AdjustTokenPrivileges(hToken, FALSE, &mut tkp, 0, 886 0 as *mut _, 0 as *mut _)); 887 }); 888 } 889 890 891 892 // Computes (value*numer)/denom without overflow, as long as both 893 // (numer*denom) and the overall result fit into i64 (which is the case 894 // for our time conversions). mul_div_i64(value: i64, numer: i64, denom: i64) -> i64895 fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { 896 let q = value / denom; 897 let r = value % denom; 898 // Decompose value as (value/denom*denom + value%denom), 899 // substitute into (value*numer)/denom and simplify. 900 // r < denom, so (denom*numer) is the upper bound of (r*numer) 901 q * numer + r * numer / denom 902 } 903 904 #[test] test_muldiv()905 fn test_muldiv() { 906 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 907 1_000_000_000_001_000); 908 assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), 909 -1_000_000_000_001_000); 910 assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 911 1_000_000_000_001_000); 912 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), 913 -1_000_000_000_001_000); 914 assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 915 1_000_000_000_001_000); 916 } 917 } 918