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(any(target_os = "emscripten", target_os = "wasi"))))] 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_os = "wasi")] 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 wasi::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME}; 143 144 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 145 pub struct SteadyTime { 146 t: u64 147 } 148 time_to_utc_tm(sec: i64, tm: &mut Tm)149 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 150 time_to_tm(sec, tm); 151 } 152 time_to_local_tm(sec: i64, tm: &mut Tm)153 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 154 // FIXME: Add timezone logic 155 time_to_tm(sec, tm); 156 } 157 utc_tm_to_time(tm: &Tm) -> i64158 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 159 tm_to_time(tm) 160 } 161 local_tm_to_time(tm: &Tm) -> i64162 pub fn local_tm_to_time(tm: &Tm) -> i64 { 163 // FIXME: Add timezone logic 164 tm_to_time(tm) 165 } 166 get_time() -> (i64, i32)167 pub fn get_time() -> (i64, i32) { 168 let ts = get_precise_ns(); 169 ( 170 ts as i64 / 1_000_000_000, 171 (ts as i64 % 1_000_000_000) as i32, 172 ) 173 } 174 get_precise_ns() -> u64175 pub fn get_precise_ns() -> u64 { 176 unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000_000) } 177 .expect("Host doesn't implement a real-time clock") 178 } 179 180 impl SteadyTime { now() -> SteadyTime181 pub fn now() -> SteadyTime { 182 SteadyTime { 183 t: unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000_000) } 184 .expect("Host doesn't implement a monotonic clock"), 185 } 186 } 187 } 188 189 impl Sub for SteadyTime { 190 type Output = Duration; sub(self, other: SteadyTime) -> Duration191 fn sub(self, other: SteadyTime) -> Duration { 192 Duration::nanoseconds(self.t as i64 - other.t as i64) 193 } 194 } 195 196 impl Sub<Duration> for SteadyTime { 197 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime198 fn sub(self, other: Duration) -> SteadyTime { 199 self + -other 200 } 201 } 202 203 impl Add<Duration> for SteadyTime { 204 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime205 fn add(self, other: Duration) -> SteadyTime { 206 let delta = other.num_nanoseconds().unwrap(); 207 SteadyTime { 208 t: (self.t as i64 + delta) as u64, 209 } 210 } 211 } 212 } 213 214 #[cfg(target_env = "sgx")] 215 mod inner { 216 use std::ops::{Add, Sub}; 217 use Tm; 218 use Duration; 219 use super::common::{time_to_tm, tm_to_time}; 220 use std::time::SystemTime; 221 222 /// The number of nanoseconds in seconds. 223 const NANOS_PER_SEC: u64 = 1_000_000_000; 224 225 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 226 pub struct SteadyTime { 227 t: Duration 228 } 229 time_to_utc_tm(sec: i64, tm: &mut Tm)230 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 231 time_to_tm(sec, tm); 232 } 233 time_to_local_tm(sec: i64, tm: &mut Tm)234 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 235 // FIXME: Add timezone logic 236 time_to_tm(sec, tm); 237 } 238 utc_tm_to_time(tm: &Tm) -> i64239 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 240 tm_to_time(tm) 241 } 242 local_tm_to_time(tm: &Tm) -> i64243 pub fn local_tm_to_time(tm: &Tm) -> i64 { 244 // FIXME: Add timezone logic 245 tm_to_time(tm) 246 } 247 get_time() -> (i64, i32)248 pub fn get_time() -> (i64, i32) { 249 SteadyTime::now().t.raw() 250 } 251 get_precise_ns() -> u64252 pub fn get_precise_ns() -> u64 { 253 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system 254 // clock is adjusted backward. 255 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 256 std_duration.as_secs() * NANOS_PER_SEC + std_duration.subsec_nanos() as u64 257 } 258 259 impl SteadyTime { now() -> SteadyTime260 pub fn now() -> SteadyTime { 261 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system 262 // clock is adjusted backward. 263 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 264 // This unwrap is safe because duration is well within the limits of i64. 265 let duration = Duration::from_std(std_duration).unwrap(); 266 SteadyTime { t: duration } 267 } 268 } 269 270 impl Sub for SteadyTime { 271 type Output = Duration; sub(self, other: SteadyTime) -> Duration272 fn sub(self, other: SteadyTime) -> Duration { 273 self.t - other.t 274 } 275 } 276 277 impl Sub<Duration> for SteadyTime { 278 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime279 fn sub(self, other: Duration) -> SteadyTime { 280 SteadyTime { t: self.t - other } 281 } 282 } 283 284 impl Add<Duration> for SteadyTime { 285 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime286 fn add(self, other: Duration) -> SteadyTime { 287 SteadyTime { t: self.t + other } 288 } 289 } 290 } 291 292 #[cfg(unix)] 293 mod inner { 294 use libc::{self, time_t}; 295 use std::mem; 296 use std::io; 297 use Tm; 298 299 #[cfg(any(target_os = "macos", target_os = "ios"))] 300 pub use self::mac::*; 301 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 302 pub use self::unix::*; 303 304 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 305 extern { 306 static timezone: time_t; 307 static altzone: time_t; 308 } 309 rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm)310 fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) { 311 tm.tm_sec = rust_tm.tm_sec; 312 tm.tm_min = rust_tm.tm_min; 313 tm.tm_hour = rust_tm.tm_hour; 314 tm.tm_mday = rust_tm.tm_mday; 315 tm.tm_mon = rust_tm.tm_mon; 316 tm.tm_year = rust_tm.tm_year; 317 tm.tm_wday = rust_tm.tm_wday; 318 tm.tm_yday = rust_tm.tm_yday; 319 tm.tm_isdst = rust_tm.tm_isdst; 320 } 321 tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm)322 fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) { 323 rust_tm.tm_sec = tm.tm_sec; 324 rust_tm.tm_min = tm.tm_min; 325 rust_tm.tm_hour = tm.tm_hour; 326 rust_tm.tm_mday = tm.tm_mday; 327 rust_tm.tm_mon = tm.tm_mon; 328 rust_tm.tm_year = tm.tm_year; 329 rust_tm.tm_wday = tm.tm_wday; 330 rust_tm.tm_yday = tm.tm_yday; 331 rust_tm.tm_isdst = tm.tm_isdst; 332 rust_tm.tm_utcoff = utcoff; 333 } 334 335 #[cfg(any(target_os = "nacl", target_os = "solaris", target_os = "illumos"))] timegm(tm: *mut libc::tm) -> time_t336 unsafe fn timegm(tm: *mut libc::tm) -> time_t { 337 use std::env::{set_var, var_os, remove_var}; 338 extern { 339 fn tzset(); 340 } 341 342 let ret; 343 344 let current_tz = var_os("TZ"); 345 set_var("TZ", "UTC"); 346 tzset(); 347 348 ret = libc::mktime(tm); 349 350 if let Some(tz) = current_tz { 351 set_var("TZ", tz); 352 } else { 353 remove_var("TZ"); 354 } 355 tzset(); 356 357 ret 358 } 359 time_to_utc_tm(sec: i64, tm: &mut Tm)360 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 361 unsafe { 362 let sec = sec as time_t; 363 let mut out = mem::zeroed(); 364 if libc::gmtime_r(&sec, &mut out).is_null() { 365 panic!("gmtime_r failed: {}", io::Error::last_os_error()); 366 } 367 tm_to_rust_tm(&out, 0, tm); 368 } 369 } 370 time_to_local_tm(sec: i64, tm: &mut Tm)371 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 372 unsafe { 373 let sec = sec as time_t; 374 let mut out = mem::zeroed(); 375 if libc::localtime_r(&sec, &mut out).is_null() { 376 panic!("localtime_r failed: {}", io::Error::last_os_error()); 377 } 378 #[cfg(any(target_os = "solaris", target_os = "illumos"))] 379 let gmtoff = { 380 ::tzset(); 381 // < 0 means we don't know; assume we're not in DST. 382 if out.tm_isdst == 0 { 383 // timezone is seconds west of UTC, tm_gmtoff is seconds east 384 -timezone 385 } else if out.tm_isdst > 0 { 386 -altzone 387 } else { 388 -timezone 389 } 390 }; 391 #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] 392 let gmtoff = out.tm_gmtoff; 393 tm_to_rust_tm(&out, gmtoff as i32, tm); 394 } 395 } 396 utc_tm_to_time(rust_tm: &Tm) -> i64397 pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 { 398 #[cfg(all(target_os = "android", target_pointer_width = "32"))] 399 use libc::timegm64 as timegm; 400 #[cfg(not(any( 401 all(target_os = "android", target_pointer_width = "32"), 402 target_os = "nacl", 403 target_os = "solaris", 404 target_os = "illumos" 405 )))] 406 use libc::timegm; 407 408 let mut tm = unsafe { mem::zeroed() }; 409 rust_tm_to_tm(rust_tm, &mut tm); 410 unsafe { timegm(&mut tm) as i64 } 411 } 412 local_tm_to_time(rust_tm: &Tm) -> i64413 pub fn local_tm_to_time(rust_tm: &Tm) -> i64 { 414 let mut tm = unsafe { mem::zeroed() }; 415 rust_tm_to_tm(rust_tm, &mut tm); 416 unsafe { libc::mktime(&mut tm) as i64 } 417 } 418 419 #[cfg(any(target_os = "macos", target_os = "ios"))] 420 mod mac { 421 #[allow(deprecated)] 422 use libc::{self, timeval, mach_timebase_info}; 423 #[allow(deprecated)] 424 use std::sync::{Once, ONCE_INIT}; 425 use std::ops::{Add, Sub}; 426 use Duration; 427 428 #[allow(deprecated)] info() -> &'static mach_timebase_info429 fn info() -> &'static mach_timebase_info { 430 static mut INFO: mach_timebase_info = mach_timebase_info { 431 numer: 0, 432 denom: 0, 433 }; 434 static ONCE: Once = ONCE_INIT; 435 436 unsafe { 437 ONCE.call_once(|| { 438 mach_timebase_info(&mut INFO); 439 }); 440 &INFO 441 } 442 } 443 get_time() -> (i64, i32)444 pub fn get_time() -> (i64, i32) { 445 use std::ptr; 446 let mut tv = timeval { tv_sec: 0, tv_usec: 0 }; 447 unsafe { libc::gettimeofday(&mut tv, ptr::null_mut()); } 448 (tv.tv_sec as i64, tv.tv_usec * 1000) 449 } 450 451 #[allow(deprecated)] 452 #[inline] get_precise_ns() -> u64453 pub fn get_precise_ns() -> u64 { 454 unsafe { 455 let time = libc::mach_absolute_time(); 456 let info = info(); 457 time * info.numer as u64 / info.denom as u64 458 } 459 } 460 461 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] 462 pub struct SteadyTime { t: u64 } 463 464 impl SteadyTime { now() -> SteadyTime465 pub fn now() -> SteadyTime { 466 SteadyTime { t: get_precise_ns() } 467 } 468 } 469 impl Sub for SteadyTime { 470 type Output = Duration; sub(self, other: SteadyTime) -> Duration471 fn sub(self, other: SteadyTime) -> Duration { 472 Duration::nanoseconds(self.t as i64 - other.t as i64) 473 } 474 } 475 impl Sub<Duration> for SteadyTime { 476 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime477 fn sub(self, other: Duration) -> SteadyTime { 478 self + -other 479 } 480 } 481 impl Add<Duration> for SteadyTime { 482 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime483 fn add(self, other: Duration) -> SteadyTime { 484 let delta = other.num_nanoseconds().unwrap(); 485 SteadyTime { 486 t: (self.t as i64 + delta) as u64 487 } 488 } 489 } 490 } 491 492 #[cfg(test)] 493 pub struct TzReset; 494 495 #[cfg(test)] set_los_angeles_time_zone() -> TzReset496 pub fn set_los_angeles_time_zone() -> TzReset { 497 use std::env; 498 env::set_var("TZ", "America/Los_Angeles"); 499 ::tzset(); 500 TzReset 501 } 502 503 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset504 pub fn set_london_with_dst_time_zone() -> TzReset { 505 use std::env; 506 env::set_var("TZ", "Europe/London"); 507 ::tzset(); 508 TzReset 509 } 510 511 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 512 mod unix { 513 use std::fmt; 514 use std::cmp::Ordering; 515 use std::ops::{Add, Sub}; 516 use libc; 517 518 use Duration; 519 get_time() -> (i64, i32)520 pub fn get_time() -> (i64, i32) { 521 let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 522 unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); } 523 (tv.tv_sec as i64, tv.tv_nsec as i32) 524 } 525 get_precise_ns() -> u64526 pub fn get_precise_ns() -> u64 { 527 let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 528 unsafe { 529 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); 530 } 531 (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) 532 } 533 534 #[derive(Copy)] 535 pub struct SteadyTime { 536 t: libc::timespec, 537 } 538 539 impl fmt::Debug for SteadyTime { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result540 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 541 write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", 542 self.t.tv_sec, self.t.tv_nsec) 543 } 544 } 545 546 impl Clone for SteadyTime { clone(&self) -> SteadyTime547 fn clone(&self) -> SteadyTime { 548 SteadyTime { t: self.t } 549 } 550 } 551 552 impl SteadyTime { now() -> SteadyTime553 pub fn now() -> SteadyTime { 554 let mut t = SteadyTime { 555 t: libc::timespec { 556 tv_sec: 0, 557 tv_nsec: 0, 558 } 559 }; 560 unsafe { 561 assert_eq!(0, libc::clock_gettime(libc::CLOCK_MONOTONIC, 562 &mut t.t)); 563 } 564 t 565 } 566 } 567 568 impl Sub for SteadyTime { 569 type Output = Duration; sub(self, other: SteadyTime) -> Duration570 fn sub(self, other: SteadyTime) -> Duration { 571 if self.t.tv_nsec >= other.t.tv_nsec { 572 Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + 573 Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) 574 } else { 575 Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + 576 Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - 577 other.t.tv_nsec as i64) 578 } 579 } 580 } 581 582 impl Sub<Duration> for SteadyTime { 583 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime584 fn sub(self, other: Duration) -> SteadyTime { 585 self + -other 586 } 587 } 588 589 impl Add<Duration> for SteadyTime { 590 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime591 fn add(mut self, other: Duration) -> SteadyTime { 592 let seconds = other.num_seconds(); 593 let nanoseconds = other - Duration::seconds(seconds); 594 let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); 595 596 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] 597 type nsec = i64; 598 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] 599 type nsec = libc::c_long; 600 601 self.t.tv_sec += seconds as libc::time_t; 602 self.t.tv_nsec += nanoseconds as nsec; 603 if self.t.tv_nsec >= ::NSEC_PER_SEC as nsec { 604 self.t.tv_nsec -= ::NSEC_PER_SEC as nsec; 605 self.t.tv_sec += 1; 606 } else if self.t.tv_nsec < 0 { 607 self.t.tv_sec -= 1; 608 self.t.tv_nsec += ::NSEC_PER_SEC as nsec; 609 } 610 self 611 } 612 } 613 614 impl PartialOrd for SteadyTime { partial_cmp(&self, other: &SteadyTime) -> Option<Ordering>615 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { 616 Some(self.cmp(other)) 617 } 618 } 619 620 impl Ord for SteadyTime { cmp(&self, other: &SteadyTime) -> Ordering621 fn cmp(&self, other: &SteadyTime) -> Ordering { 622 match self.t.tv_sec.cmp(&other.t.tv_sec) { 623 Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), 624 ord => ord 625 } 626 } 627 } 628 629 impl PartialEq for SteadyTime { eq(&self, other: &SteadyTime) -> bool630 fn eq(&self, other: &SteadyTime) -> bool { 631 self.t.tv_sec == other.t.tv_sec && 632 self.t.tv_nsec == other.t.tv_nsec 633 } 634 } 635 636 impl Eq for SteadyTime {} 637 638 } 639 } 640 641 #[cfg(windows)] 642 #[allow(non_snake_case)] 643 mod inner { 644 use std::io; 645 use std::mem; 646 #[allow(deprecated)] 647 use std::sync::{Once, ONCE_INIT}; 648 use std::ops::{Add, Sub}; 649 use {Tm, Duration}; 650 651 use winapi::um::winnt::*; 652 use winapi::shared::minwindef::*; 653 use winapi::um::minwinbase::SYSTEMTIME; 654 use winapi::um::profileapi::*; 655 use winapi::um::timezoneapi::*; 656 use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; 657 frequency() -> i64658 fn frequency() -> i64 { 659 static mut FREQUENCY: i64 = 0; 660 #[allow(deprecated)] 661 static ONCE: Once = ONCE_INIT; 662 663 unsafe { 664 ONCE.call_once(|| { 665 let mut l = i64_to_large_integer(0); 666 QueryPerformanceFrequency(&mut l); 667 FREQUENCY = large_integer_to_i64(l); 668 }); 669 FREQUENCY 670 } 671 } 672 i64_to_large_integer(i: i64) -> LARGE_INTEGER673 fn i64_to_large_integer(i: i64) -> LARGE_INTEGER { 674 unsafe { 675 let mut large_integer: LARGE_INTEGER = mem::zeroed(); 676 *large_integer.QuadPart_mut() = i; 677 large_integer 678 } 679 } 680 large_integer_to_i64(l: LARGE_INTEGER) -> i64681 fn large_integer_to_i64(l: LARGE_INTEGER) -> i64 { 682 unsafe { 683 *l.QuadPart() 684 } 685 } 686 687 const HECTONANOSECS_IN_SEC: i64 = 10_000_000; 688 const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; 689 time_to_file_time(sec: i64) -> FILETIME690 fn time_to_file_time(sec: i64) -> FILETIME { 691 let t = (((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH)) as u64; 692 FILETIME { 693 dwLowDateTime: t as DWORD, 694 dwHighDateTime: (t >> 32) as DWORD 695 } 696 } 697 file_time_as_u64(ft: &FILETIME) -> u64698 fn file_time_as_u64(ft: &FILETIME) -> u64 { 699 ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) 700 } 701 file_time_to_nsec(ft: &FILETIME) -> i32702 fn file_time_to_nsec(ft: &FILETIME) -> i32 { 703 let t = file_time_as_u64(ft) as i64; 704 ((t % HECTONANOSECS_IN_SEC) * 100) as i32 705 } 706 file_time_to_unix_seconds(ft: &FILETIME) -> i64707 fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { 708 let t = file_time_as_u64(ft) as i64; 709 ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 710 } 711 system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME712 fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { 713 unsafe { 714 let mut ft = mem::zeroed(); 715 SystemTimeToFileTime(sys, &mut ft); 716 ft 717 } 718 } 719 tm_to_system_time(tm: &Tm) -> SYSTEMTIME720 fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { 721 let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; 722 sys.wSecond = tm.tm_sec as WORD; 723 sys.wMinute = tm.tm_min as WORD; 724 sys.wHour = tm.tm_hour as WORD; 725 sys.wDay = tm.tm_mday as WORD; 726 sys.wDayOfWeek = tm.tm_wday as WORD; 727 sys.wMonth = (tm.tm_mon + 1) as WORD; 728 sys.wYear = (tm.tm_year + 1900) as WORD; 729 sys 730 } 731 system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm)732 fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { 733 tm.tm_sec = sys.wSecond as i32; 734 tm.tm_min = sys.wMinute as i32; 735 tm.tm_hour = sys.wHour as i32; 736 tm.tm_mday = sys.wDay as i32; 737 tm.tm_wday = sys.wDayOfWeek as i32; 738 tm.tm_mon = (sys.wMonth - 1) as i32; 739 tm.tm_year = (sys.wYear - 1900) as i32; 740 tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); 741 742 fn yday(year: i32, month: i32, day: i32) -> i32 { 743 let leap = if month > 2 { 744 if year % 4 == 0 { 1 } else { 2 } 745 } else { 746 0 747 }; 748 let july = if month > 7 { 1 } else { 0 }; 749 750 (month - 1) * 30 + month / 2 + (day - 1) - leap + july 751 } 752 } 753 754 macro_rules! call { 755 ($name:ident($($arg:expr),*)) => { 756 if $name($($arg),*) == 0 { 757 panic!(concat!(stringify!($name), " failed with: {}"), 758 io::Error::last_os_error()); 759 } 760 } 761 } 762 time_to_utc_tm(sec: i64, tm: &mut Tm)763 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 764 let mut out = unsafe { mem::zeroed() }; 765 let ft = time_to_file_time(sec); 766 unsafe { 767 call!(FileTimeToSystemTime(&ft, &mut out)); 768 } 769 system_time_to_tm(&out, tm); 770 tm.tm_utcoff = 0; 771 } 772 time_to_local_tm(sec: i64, tm: &mut Tm)773 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 774 let ft = time_to_file_time(sec); 775 unsafe { 776 let mut utc = mem::zeroed(); 777 let mut local = mem::zeroed(); 778 call!(FileTimeToSystemTime(&ft, &mut utc)); 779 call!(SystemTimeToTzSpecificLocalTime(0 as *const _, 780 &mut utc, &mut local)); 781 system_time_to_tm(&local, tm); 782 783 let local = system_time_to_file_time(&local); 784 let local_sec = file_time_to_unix_seconds(&local); 785 786 let mut tz = mem::zeroed(); 787 GetTimeZoneInformation(&mut tz); 788 789 // SystemTimeToTzSpecificLocalTime already applied the biases so 790 // check if it non standard 791 tm.tm_utcoff = (local_sec - sec) as i32; 792 tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 793 0 794 } else { 795 1 796 }; 797 } 798 } 799 utc_tm_to_time(tm: &Tm) -> i64800 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 801 unsafe { 802 let mut ft = mem::zeroed(); 803 let sys_time = tm_to_system_time(tm); 804 call!(SystemTimeToFileTime(&sys_time, &mut ft)); 805 file_time_to_unix_seconds(&ft) 806 } 807 } 808 local_tm_to_time(tm: &Tm) -> i64809 pub fn local_tm_to_time(tm: &Tm) -> i64 { 810 unsafe { 811 let mut ft = mem::zeroed(); 812 let mut utc = mem::zeroed(); 813 let mut sys_time = tm_to_system_time(tm); 814 call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, 815 &mut sys_time, &mut utc)); 816 call!(SystemTimeToFileTime(&utc, &mut ft)); 817 file_time_to_unix_seconds(&ft) 818 } 819 } 820 get_time() -> (i64, i32)821 pub fn get_time() -> (i64, i32) { 822 unsafe { 823 let mut ft = mem::zeroed(); 824 GetSystemTimeAsFileTime(&mut ft); 825 (file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft)) 826 } 827 } 828 get_precise_ns() -> u64829 pub fn get_precise_ns() -> u64 { 830 let mut ticks = i64_to_large_integer(0); 831 unsafe { 832 assert!(QueryPerformanceCounter(&mut ticks) == 1); 833 } 834 mul_div_i64(large_integer_to_i64(ticks), 1000000000, frequency()) as u64 835 836 } 837 838 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] 839 pub struct SteadyTime { 840 t: i64, 841 } 842 843 impl SteadyTime { now() -> SteadyTime844 pub fn now() -> SteadyTime { 845 let mut l = i64_to_large_integer(0); 846 unsafe { QueryPerformanceCounter(&mut l); } 847 SteadyTime { t : large_integer_to_i64(l) } 848 } 849 } 850 851 impl Sub for SteadyTime { 852 type Output = Duration; sub(self, other: SteadyTime) -> Duration853 fn sub(self, other: SteadyTime) -> Duration { 854 let diff = self.t as i64 - other.t as i64; 855 Duration::nanoseconds(mul_div_i64(diff, 1000000000, 856 frequency())) 857 } 858 } 859 860 impl Sub<Duration> for SteadyTime { 861 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime862 fn sub(self, other: Duration) -> SteadyTime { 863 self + -other 864 } 865 } 866 867 impl Add<Duration> for SteadyTime { 868 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime869 fn add(mut self, other: Duration) -> SteadyTime { 870 self.t += (other.num_microseconds().unwrap() * frequency() / 871 1_000_000) as i64; 872 self 873 } 874 } 875 876 #[cfg(test)] 877 pub struct TzReset { 878 old: TIME_ZONE_INFORMATION, 879 } 880 881 #[cfg(test)] 882 impl Drop for TzReset { drop(&mut self)883 fn drop(&mut self) { 884 unsafe { 885 call!(SetTimeZoneInformation(&self.old)); 886 } 887 } 888 } 889 890 #[cfg(test)] set_los_angeles_time_zone() -> TzReset891 pub fn set_los_angeles_time_zone() -> TzReset { 892 acquire_privileges(); 893 894 unsafe { 895 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 896 GetTimeZoneInformation(&mut tz); 897 let ret = TzReset { old: tz }; 898 tz.Bias = 60 * 8; 899 call!(SetTimeZoneInformation(&tz)); 900 return ret 901 } 902 } 903 904 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset905 pub fn set_london_with_dst_time_zone() -> TzReset { 906 acquire_privileges(); 907 908 unsafe { 909 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 910 GetTimeZoneInformation(&mut tz); 911 let ret = TzReset { old: tz }; 912 // Since date set precisely this is 2015's dates 913 tz.Bias = 0; 914 tz.DaylightBias = -60; 915 tz.DaylightDate.wYear = 0; 916 tz.DaylightDate.wMonth = 3; 917 tz.DaylightDate.wDayOfWeek = 0; 918 tz.DaylightDate.wDay = 5; 919 tz.DaylightDate.wHour = 2; 920 tz.StandardBias = 0; 921 tz.StandardDate.wYear = 0; 922 tz.StandardDate.wMonth = 10; 923 tz.StandardDate.wDayOfWeek = 0; 924 tz.StandardDate.wDay = 5; 925 tz.StandardDate.wHour = 2; 926 call!(SetTimeZoneInformation(&tz)); 927 return ret 928 } 929 } 930 931 // Ensures that this process has the necessary privileges to set a new time 932 // zone, and this is all transcribed from: 933 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724944%28v=vs.85%29.aspx 934 #[cfg(test)] acquire_privileges()935 fn acquire_privileges() { 936 use winapi::um::processthreadsapi::*; 937 use winapi::um::winbase::LookupPrivilegeValueA; 938 const SE_PRIVILEGE_ENABLED: DWORD = 2; 939 #[allow(deprecated)] 940 static INIT: Once = ONCE_INIT; 941 942 // TODO: FIXME 943 extern "system" { 944 fn AdjustTokenPrivileges( 945 TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES, 946 BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD, 947 ) -> BOOL; 948 } 949 950 INIT.call_once(|| unsafe { 951 let mut hToken = 0 as *mut _; 952 call!(OpenProcessToken(GetCurrentProcess(), 953 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 954 &mut hToken)); 955 956 let mut tkp = mem::zeroed::<TOKEN_PRIVILEGES>(); 957 assert_eq!(tkp.Privileges.len(), 1); 958 let c = ::std::ffi::CString::new("SeTimeZonePrivilege").unwrap(); 959 call!(LookupPrivilegeValueA(0 as *const _, c.as_ptr(), 960 &mut tkp.Privileges[0].Luid)); 961 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; 962 tkp.PrivilegeCount = 1; 963 call!(AdjustTokenPrivileges(hToken, FALSE, &mut tkp, 0, 964 0 as *mut _, 0 as *mut _)); 965 }); 966 } 967 968 969 970 // Computes (value*numer)/denom without overflow, as long as both 971 // (numer*denom) and the overall result fit into i64 (which is the case 972 // for our time conversions). mul_div_i64(value: i64, numer: i64, denom: i64) -> i64973 fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { 974 let q = value / denom; 975 let r = value % denom; 976 // Decompose value as (value/denom*denom + value%denom), 977 // substitute into (value*numer)/denom and simplify. 978 // r < denom, so (denom*numer) is the upper bound of (r*numer) 979 q * numer + r * numer / denom 980 } 981 982 #[test] test_muldiv()983 fn test_muldiv() { 984 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 985 1_000_000_000_001_000); 986 assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), 987 -1_000_000_000_001_000); 988 assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 989 1_000_000_000_001_000); 990 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), 991 -1_000_000_000_001_000); 992 assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 993 1_000_000_000_001_000); 994 } 995 } 996