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_os = "redox", 8 target_env = "sgx" 9 ))] 10 mod common { 11 use Tm; 12 time_to_tm(ts: i64, tm: &mut Tm)13 pub fn time_to_tm(ts: i64, tm: &mut Tm) { 14 let leapyear = |year| -> bool { 15 year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) 16 }; 17 18 static _ytab: [[i64; 12]; 2] = [ 19 [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ], 20 [ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] 21 ]; 22 23 let mut year = 1970; 24 25 let dayclock = ts % 86400; 26 let mut dayno = ts / 86400; 27 28 tm.tm_sec = (dayclock % 60) as i32; 29 tm.tm_min = ((dayclock % 3600) / 60) as i32; 30 tm.tm_hour = (dayclock / 3600) as i32; 31 tm.tm_wday = ((dayno + 4) % 7) as i32; 32 loop { 33 let yearsize = if leapyear(year) { 34 366 35 } else { 36 365 37 }; 38 if dayno >= yearsize { 39 dayno -= yearsize; 40 year += 1; 41 } else { 42 break; 43 } 44 } 45 tm.tm_year = (year - 1900) as i32; 46 tm.tm_yday = dayno as i32; 47 let mut mon = 0; 48 while dayno >= _ytab[if leapyear(year) { 1 } else { 0 }][mon] { 49 dayno -= _ytab[if leapyear(year) { 1 } else { 0 }][mon]; 50 mon += 1; 51 } 52 tm.tm_mon = mon as i32; 53 tm.tm_mday = dayno as i32 + 1; 54 tm.tm_isdst = 0; 55 } 56 tm_to_time(tm: &Tm) -> i6457 pub fn tm_to_time(tm: &Tm) -> i64 { 58 let mut y = tm.tm_year as i64 + 1900; 59 let mut m = tm.tm_mon as i64 + 1; 60 if m <= 2 { 61 y -= 1; 62 m += 12; 63 } 64 let d = tm.tm_mday as i64; 65 let h = tm.tm_hour as i64; 66 let mi = tm.tm_min as i64; 67 let s = tm.tm_sec as i64; 68 (365*y + y/4 - y/100 + y/400 + 3*(m+1)/5 + 30*m + d - 719561) 69 * 86400 + 3600 * h + 60 * mi + s 70 } 71 } 72 73 #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] 74 mod inner { 75 use std::ops::{Add, Sub}; 76 use Tm; 77 use Duration; 78 use super::common::{time_to_tm, tm_to_time}; 79 80 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 81 pub struct SteadyTime; 82 time_to_utc_tm(sec: i64, tm: &mut Tm)83 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 84 time_to_tm(sec, tm); 85 } 86 time_to_local_tm(sec: i64, tm: &mut Tm)87 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 88 // FIXME: Add timezone logic 89 time_to_tm(sec, tm); 90 } 91 utc_tm_to_time(tm: &Tm) -> i6492 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 93 tm_to_time(tm) 94 } 95 local_tm_to_time(tm: &Tm) -> i6496 pub fn local_tm_to_time(tm: &Tm) -> i64 { 97 // FIXME: Add timezone logic 98 tm_to_time(tm) 99 } 100 get_time() -> (i64, i32)101 pub fn get_time() -> (i64, i32) { 102 unimplemented!() 103 } 104 get_precise_ns() -> u64105 pub fn get_precise_ns() -> u64 { 106 unimplemented!() 107 } 108 109 impl SteadyTime { now() -> SteadyTime110 pub fn now() -> SteadyTime { 111 unimplemented!() 112 } 113 } 114 115 impl Sub for SteadyTime { 116 type Output = Duration; sub(self, _other: SteadyTime) -> Duration117 fn sub(self, _other: SteadyTime) -> Duration { 118 unimplemented!() 119 } 120 } 121 122 impl Sub<Duration> for SteadyTime { 123 type Output = SteadyTime; sub(self, _other: Duration) -> SteadyTime124 fn sub(self, _other: Duration) -> SteadyTime { 125 unimplemented!() 126 } 127 } 128 129 impl Add<Duration> for SteadyTime { 130 type Output = SteadyTime; add(self, _other: Duration) -> SteadyTime131 fn add(self, _other: Duration) -> SteadyTime { 132 unimplemented!() 133 } 134 } 135 } 136 137 #[cfg(target_os = "redox")] 138 mod inner { 139 use std::fmt; 140 use std::cmp::Ordering; 141 use std::ops::{Add, Sub}; 142 use syscall; 143 use super::common::{time_to_tm, tm_to_time}; 144 145 use Duration; 146 use Tm; 147 time_to_utc_tm(sec: i64, tm: &mut Tm)148 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 149 time_to_tm(sec, tm); 150 } 151 time_to_local_tm(sec: i64, tm: &mut Tm)152 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 153 // FIXME: Add timezone logic 154 time_to_tm(sec, tm); 155 } 156 utc_tm_to_time(tm: &Tm) -> i64157 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 158 tm_to_time(tm) 159 } 160 local_tm_to_time(tm: &Tm) -> i64161 pub fn local_tm_to_time(tm: &Tm) -> i64 { 162 // FIXME: Add timezone logic 163 tm_to_time(tm) 164 } 165 get_time() -> (i64, i32)166 pub fn get_time() -> (i64, i32) { 167 let mut tv = syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 }; 168 syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut tv).unwrap(); 169 (tv.tv_sec as i64, tv.tv_nsec as i32) 170 } 171 get_precise_ns() -> u64172 pub fn get_precise_ns() -> u64 { 173 let mut ts = syscall::TimeSpec { tv_sec: 0, tv_nsec: 0 }; 174 syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut ts).unwrap(); 175 (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) 176 } 177 178 #[derive(Copy)] 179 pub struct SteadyTime { 180 t: syscall::TimeSpec, 181 } 182 183 impl fmt::Debug for SteadyTime { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result184 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 185 write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", 186 self.t.tv_sec, self.t.tv_nsec) 187 } 188 } 189 190 impl Clone for SteadyTime { clone(&self) -> SteadyTime191 fn clone(&self) -> SteadyTime { 192 SteadyTime { t: self.t } 193 } 194 } 195 196 impl SteadyTime { now() -> SteadyTime197 pub fn now() -> SteadyTime { 198 let mut t = SteadyTime { 199 t: syscall::TimeSpec { 200 tv_sec: 0, 201 tv_nsec: 0, 202 } 203 }; 204 syscall::clock_gettime(syscall::CLOCK_MONOTONIC, &mut t.t).unwrap(); 205 t 206 } 207 } 208 209 impl Sub for SteadyTime { 210 type Output = Duration; sub(self, other: SteadyTime) -> Duration211 fn sub(self, other: SteadyTime) -> Duration { 212 if self.t.tv_nsec >= other.t.tv_nsec { 213 Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + 214 Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) 215 } else { 216 Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + 217 Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - 218 other.t.tv_nsec as i64) 219 } 220 } 221 } 222 223 impl Sub<Duration> for SteadyTime { 224 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime225 fn sub(self, other: Duration) -> SteadyTime { 226 self + -other 227 } 228 } 229 230 impl Add<Duration> for SteadyTime { 231 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime232 fn add(mut self, other: Duration) -> SteadyTime { 233 let seconds = other.num_seconds(); 234 let nanoseconds = other - Duration::seconds(seconds); 235 let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); 236 self.t.tv_sec += seconds; 237 self.t.tv_nsec += nanoseconds as i32; 238 if self.t.tv_nsec >= ::NSEC_PER_SEC { 239 self.t.tv_nsec -= ::NSEC_PER_SEC; 240 self.t.tv_sec += 1; 241 } else if self.t.tv_nsec < 0 { 242 self.t.tv_sec -= 1; 243 self.t.tv_nsec += ::NSEC_PER_SEC; 244 } 245 self 246 } 247 } 248 249 impl PartialOrd for SteadyTime { partial_cmp(&self, other: &SteadyTime) -> Option<Ordering>250 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { 251 Some(self.cmp(other)) 252 } 253 } 254 255 impl Ord for SteadyTime { cmp(&self, other: &SteadyTime) -> Ordering256 fn cmp(&self, other: &SteadyTime) -> Ordering { 257 match self.t.tv_sec.cmp(&other.t.tv_sec) { 258 Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), 259 ord => ord 260 } 261 } 262 } 263 264 impl PartialEq for SteadyTime { eq(&self, other: &SteadyTime) -> bool265 fn eq(&self, other: &SteadyTime) -> bool { 266 self.t.tv_sec == other.t.tv_sec && 267 self.t.tv_nsec == other.t.tv_nsec 268 } 269 } 270 271 impl Eq for SteadyTime {} 272 } 273 274 #[cfg(target_env = "sgx")] 275 mod inner { 276 use std::ops::{Add, Sub}; 277 use Tm; 278 use Duration; 279 use super::common::{time_to_tm, tm_to_time}; 280 use std::time::SystemTime; 281 282 /// The number of nanoseconds in seconds. 283 const NANOS_PER_SEC: u64 = 1_000_000_000; 284 285 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] 286 pub struct SteadyTime { 287 t: Duration 288 } 289 time_to_utc_tm(sec: i64, tm: &mut Tm)290 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 291 time_to_tm(sec, tm); 292 } 293 time_to_local_tm(sec: i64, tm: &mut Tm)294 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 295 // FIXME: Add timezone logic 296 time_to_tm(sec, tm); 297 } 298 utc_tm_to_time(tm: &Tm) -> i64299 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 300 tm_to_time(tm) 301 } 302 local_tm_to_time(tm: &Tm) -> i64303 pub fn local_tm_to_time(tm: &Tm) -> i64 { 304 // FIXME: Add timezone logic 305 tm_to_time(tm) 306 } 307 get_time() -> (i64, i32)308 pub fn get_time() -> (i64, i32) { 309 SteadyTime::now().t.raw() 310 } 311 get_precise_ns() -> u64312 pub fn get_precise_ns() -> u64 { 313 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system clock is adjusted backward. 314 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 315 std_duration.as_secs() * NANOS_PER_SEC + std_duration.subsec_nanos() as u64 316 } 317 318 impl SteadyTime { now() -> SteadyTime319 pub fn now() -> SteadyTime { 320 // This unwrap is safe because current time is well ahead of UNIX_EPOCH, unless system clock is adjusted backward. 321 let std_duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap(); 322 // This unwrap is safe because duration is well within the limits of i64. 323 let duration = Duration::from_std(std_duration).unwrap(); 324 SteadyTime { t: duration } 325 } 326 } 327 328 impl Sub for SteadyTime { 329 type Output = Duration; sub(self, other: SteadyTime) -> Duration330 fn sub(self, other: SteadyTime) -> Duration { 331 self.t - other.t 332 } 333 } 334 335 impl Sub<Duration> for SteadyTime { 336 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime337 fn sub(self, other: Duration) -> SteadyTime { 338 SteadyTime { t: self.t - other } 339 } 340 } 341 342 impl Add<Duration> for SteadyTime { 343 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime344 fn add(self, other: Duration) -> SteadyTime { 345 SteadyTime { t: self.t + other } 346 } 347 } 348 } 349 350 #[cfg(unix)] 351 mod inner { 352 use libc::{self, time_t}; 353 use std::mem; 354 use std::io; 355 use Tm; 356 357 #[cfg(any(target_os = "macos", target_os = "ios"))] 358 pub use self::mac::*; 359 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 360 pub use self::unix::*; 361 362 #[cfg(target_os = "solaris")] 363 extern { 364 static timezone: time_t; 365 static altzone: time_t; 366 } 367 rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm)368 fn rust_tm_to_tm(rust_tm: &Tm, tm: &mut libc::tm) { 369 tm.tm_sec = rust_tm.tm_sec; 370 tm.tm_min = rust_tm.tm_min; 371 tm.tm_hour = rust_tm.tm_hour; 372 tm.tm_mday = rust_tm.tm_mday; 373 tm.tm_mon = rust_tm.tm_mon; 374 tm.tm_year = rust_tm.tm_year; 375 tm.tm_wday = rust_tm.tm_wday; 376 tm.tm_yday = rust_tm.tm_yday; 377 tm.tm_isdst = rust_tm.tm_isdst; 378 } 379 tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm)380 fn tm_to_rust_tm(tm: &libc::tm, utcoff: i32, rust_tm: &mut Tm) { 381 rust_tm.tm_sec = tm.tm_sec; 382 rust_tm.tm_min = tm.tm_min; 383 rust_tm.tm_hour = tm.tm_hour; 384 rust_tm.tm_mday = tm.tm_mday; 385 rust_tm.tm_mon = tm.tm_mon; 386 rust_tm.tm_year = tm.tm_year; 387 rust_tm.tm_wday = tm.tm_wday; 388 rust_tm.tm_yday = tm.tm_yday; 389 rust_tm.tm_isdst = tm.tm_isdst; 390 rust_tm.tm_utcoff = utcoff; 391 } 392 393 #[cfg(any(target_os = "nacl", target_os = "solaris"))] timegm(tm: *mut libc::tm) -> time_t394 unsafe fn timegm(tm: *mut libc::tm) -> time_t { 395 use std::env::{set_var, var_os, remove_var}; 396 extern { 397 fn tzset(); 398 } 399 400 let ret; 401 402 let current_tz = var_os("TZ"); 403 set_var("TZ", "UTC"); 404 tzset(); 405 406 ret = libc::mktime(tm); 407 408 if let Some(tz) = current_tz { 409 set_var("TZ", tz); 410 } else { 411 remove_var("TZ"); 412 } 413 tzset(); 414 415 ret 416 } 417 time_to_utc_tm(sec: i64, tm: &mut Tm)418 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 419 unsafe { 420 let sec = sec as time_t; 421 let mut out = mem::zeroed(); 422 if libc::gmtime_r(&sec, &mut out).is_null() { 423 panic!("gmtime_r failed: {}", io::Error::last_os_error()); 424 } 425 tm_to_rust_tm(&out, 0, tm); 426 } 427 } 428 time_to_local_tm(sec: i64, tm: &mut Tm)429 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 430 unsafe { 431 let sec = sec as time_t; 432 let mut out = mem::zeroed(); 433 if libc::localtime_r(&sec, &mut out).is_null() { 434 panic!("localtime_r failed: {}", io::Error::last_os_error()); 435 } 436 #[cfg(target_os = "solaris")] 437 let gmtoff = { 438 ::tzset(); 439 // < 0 means we don't know; assume we're not in DST. 440 if out.tm_isdst == 0 { 441 // timezone is seconds west of UTC, tm_gmtoff is seconds east 442 -timezone 443 } else if out.tm_isdst > 0 { 444 -altzone 445 } else { 446 -timezone 447 } 448 }; 449 #[cfg(not(target_os = "solaris"))] 450 let gmtoff = out.tm_gmtoff; 451 tm_to_rust_tm(&out, gmtoff as i32, tm); 452 } 453 } 454 utc_tm_to_time(rust_tm: &Tm) -> i64455 pub fn utc_tm_to_time(rust_tm: &Tm) -> i64 { 456 #[cfg(all(target_os = "android", target_pointer_width = "32"))] 457 use libc::timegm64 as timegm; 458 #[cfg(not(any(all(target_os = "android", target_pointer_width = "32"), target_os = "nacl", target_os = "solaris")))] 459 use libc::timegm; 460 461 let mut tm = unsafe { mem::zeroed() }; 462 rust_tm_to_tm(rust_tm, &mut tm); 463 unsafe { timegm(&mut tm) as i64 } 464 } 465 local_tm_to_time(rust_tm: &Tm) -> i64466 pub fn local_tm_to_time(rust_tm: &Tm) -> i64 { 467 let mut tm = unsafe { mem::zeroed() }; 468 rust_tm_to_tm(rust_tm, &mut tm); 469 unsafe { libc::mktime(&mut tm) as i64 } 470 } 471 472 #[cfg(any(target_os = "macos", target_os = "ios"))] 473 mod mac { 474 use libc::{self, timeval, mach_timebase_info}; 475 use std::sync::{Once, ONCE_INIT}; 476 use std::ops::{Add, Sub}; 477 use Duration; 478 info() -> &'static mach_timebase_info479 fn info() -> &'static mach_timebase_info { 480 static mut INFO: mach_timebase_info = mach_timebase_info { 481 numer: 0, 482 denom: 0, 483 }; 484 static ONCE: Once = ONCE_INIT; 485 486 unsafe { 487 ONCE.call_once(|| { 488 mach_timebase_info(&mut INFO); 489 }); 490 &INFO 491 } 492 } 493 get_time() -> (i64, i32)494 pub fn get_time() -> (i64, i32) { 495 use std::ptr; 496 let mut tv = timeval { tv_sec: 0, tv_usec: 0 }; 497 unsafe { libc::gettimeofday(&mut tv, ptr::null_mut()); } 498 (tv.tv_sec as i64, tv.tv_usec * 1000) 499 } 500 501 #[inline] get_precise_ns() -> u64502 pub fn get_precise_ns() -> u64 { 503 unsafe { 504 let time = libc::mach_absolute_time(); 505 let info = info(); 506 time * info.numer as u64 / info.denom as u64 507 } 508 } 509 510 #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)] 511 pub struct SteadyTime { t: u64 } 512 513 impl SteadyTime { now() -> SteadyTime514 pub fn now() -> SteadyTime { 515 SteadyTime { t: get_precise_ns() } 516 } 517 } 518 impl Sub for SteadyTime { 519 type Output = Duration; sub(self, other: SteadyTime) -> Duration520 fn sub(self, other: SteadyTime) -> Duration { 521 Duration::nanoseconds(self.t as i64 - other.t as i64) 522 } 523 } 524 impl Sub<Duration> for SteadyTime { 525 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime526 fn sub(self, other: Duration) -> SteadyTime { 527 self + -other 528 } 529 } 530 impl Add<Duration> for SteadyTime { 531 type Output = SteadyTime; add(self, other: Duration) -> SteadyTime532 fn add(self, other: Duration) -> SteadyTime { 533 let delta = other.num_nanoseconds().unwrap(); 534 SteadyTime { 535 t: (self.t as i64 + delta) as u64 536 } 537 } 538 } 539 } 540 541 #[cfg(test)] 542 pub struct TzReset; 543 544 #[cfg(test)] set_los_angeles_time_zone() -> TzReset545 pub fn set_los_angeles_time_zone() -> TzReset { 546 use std::env; 547 env::set_var("TZ", "America/Los_Angeles"); 548 ::tzset(); 549 TzReset 550 } 551 552 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset553 pub fn set_london_with_dst_time_zone() -> TzReset { 554 use std::env; 555 env::set_var("TZ", "Europe/London"); 556 ::tzset(); 557 TzReset 558 } 559 560 #[cfg(all(not(target_os = "macos"), not(target_os = "ios")))] 561 mod unix { 562 use std::fmt; 563 use std::cmp::Ordering; 564 use std::ops::{Add, Sub}; 565 use libc; 566 567 use Duration; 568 get_time() -> (i64, i32)569 pub fn get_time() -> (i64, i32) { 570 let mut tv = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 571 unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, &mut tv); } 572 (tv.tv_sec as i64, tv.tv_nsec as i32) 573 } 574 get_precise_ns() -> u64575 pub fn get_precise_ns() -> u64 { 576 let mut ts = libc::timespec { tv_sec: 0, tv_nsec: 0 }; 577 unsafe { 578 libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut ts); 579 } 580 (ts.tv_sec as u64) * 1000000000 + (ts.tv_nsec as u64) 581 } 582 583 #[derive(Copy)] 584 pub struct SteadyTime { 585 t: libc::timespec, 586 } 587 588 impl fmt::Debug for SteadyTime { fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result589 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 590 write!(fmt, "SteadyTime {{ tv_sec: {:?}, tv_nsec: {:?} }}", 591 self.t.tv_sec, self.t.tv_nsec) 592 } 593 } 594 595 impl Clone for SteadyTime { clone(&self) -> SteadyTime596 fn clone(&self) -> SteadyTime { 597 SteadyTime { t: self.t } 598 } 599 } 600 601 impl SteadyTime { now() -> SteadyTime602 pub fn now() -> SteadyTime { 603 let mut t = SteadyTime { 604 t: libc::timespec { 605 tv_sec: 0, 606 tv_nsec: 0, 607 } 608 }; 609 unsafe { 610 assert_eq!(0, libc::clock_gettime(libc::CLOCK_MONOTONIC, 611 &mut t.t)); 612 } 613 t 614 } 615 } 616 617 impl Sub for SteadyTime { 618 type Output = Duration; sub(self, other: SteadyTime) -> Duration619 fn sub(self, other: SteadyTime) -> Duration { 620 if self.t.tv_nsec >= other.t.tv_nsec { 621 Duration::seconds(self.t.tv_sec as i64 - other.t.tv_sec as i64) + 622 Duration::nanoseconds(self.t.tv_nsec as i64 - other.t.tv_nsec as i64) 623 } else { 624 Duration::seconds(self.t.tv_sec as i64 - 1 - other.t.tv_sec as i64) + 625 Duration::nanoseconds(self.t.tv_nsec as i64 + ::NSEC_PER_SEC as i64 - 626 other.t.tv_nsec as i64) 627 } 628 } 629 } 630 631 impl Sub<Duration> for SteadyTime { 632 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime633 fn sub(self, other: Duration) -> SteadyTime { 634 self + -other 635 } 636 } 637 638 impl Add<Duration> for SteadyTime { 639 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime640 fn add(mut self, other: Duration) -> SteadyTime { 641 let seconds = other.num_seconds(); 642 let nanoseconds = other - Duration::seconds(seconds); 643 let nanoseconds = nanoseconds.num_nanoseconds().unwrap(); 644 645 #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] 646 type nsec = i64; 647 #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] 648 type nsec = libc::c_long; 649 650 self.t.tv_sec += seconds as libc::time_t; 651 self.t.tv_nsec += nanoseconds as nsec; 652 if self.t.tv_nsec >= ::NSEC_PER_SEC as nsec { 653 self.t.tv_nsec -= ::NSEC_PER_SEC as nsec; 654 self.t.tv_sec += 1; 655 } else if self.t.tv_nsec < 0 { 656 self.t.tv_sec -= 1; 657 self.t.tv_nsec += ::NSEC_PER_SEC as nsec; 658 } 659 self 660 } 661 } 662 663 impl PartialOrd for SteadyTime { partial_cmp(&self, other: &SteadyTime) -> Option<Ordering>664 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> { 665 Some(self.cmp(other)) 666 } 667 } 668 669 impl Ord for SteadyTime { cmp(&self, other: &SteadyTime) -> Ordering670 fn cmp(&self, other: &SteadyTime) -> Ordering { 671 match self.t.tv_sec.cmp(&other.t.tv_sec) { 672 Ordering::Equal => self.t.tv_nsec.cmp(&other.t.tv_nsec), 673 ord => ord 674 } 675 } 676 } 677 678 impl PartialEq for SteadyTime { eq(&self, other: &SteadyTime) -> bool679 fn eq(&self, other: &SteadyTime) -> bool { 680 self.t.tv_sec == other.t.tv_sec && 681 self.t.tv_nsec == other.t.tv_nsec 682 } 683 } 684 685 impl Eq for SteadyTime {} 686 687 } 688 } 689 690 #[cfg(windows)] 691 #[allow(non_snake_case)] 692 mod inner { 693 use std::io; 694 use std::mem; 695 use std::sync::{Once, ONCE_INIT}; 696 use std::ops::{Add, Sub}; 697 use {Tm, Duration}; 698 699 use winapi::um::winnt::*; 700 use winapi::shared::minwindef::*; 701 use winapi::um::minwinbase::SYSTEMTIME; 702 use winapi::um::profileapi::*; 703 use winapi::um::timezoneapi::*; 704 use winapi::um::sysinfoapi::GetSystemTimeAsFileTime; 705 frequency() -> i64706 fn frequency() -> i64 { 707 static mut FREQUENCY: i64 = 0; 708 static ONCE: Once = ONCE_INIT; 709 710 unsafe { 711 ONCE.call_once(|| { 712 let mut l = i64_to_large_integer(0); 713 QueryPerformanceFrequency(&mut l); 714 FREQUENCY = large_integer_to_i64(l); 715 }); 716 FREQUENCY 717 } 718 } 719 i64_to_large_integer(i: i64) -> LARGE_INTEGER720 fn i64_to_large_integer(i: i64) -> LARGE_INTEGER { 721 unsafe { 722 let mut large_integer: LARGE_INTEGER = mem::zeroed(); 723 *large_integer.QuadPart_mut() = i; 724 large_integer 725 } 726 } 727 large_integer_to_i64(l: LARGE_INTEGER) -> i64728 fn large_integer_to_i64(l: LARGE_INTEGER) -> i64 { 729 unsafe { 730 *l.QuadPart() 731 } 732 } 733 734 const HECTONANOSECS_IN_SEC: i64 = 10_000_000; 735 const HECTONANOSEC_TO_UNIX_EPOCH: i64 = 11_644_473_600 * HECTONANOSECS_IN_SEC; 736 time_to_file_time(sec: i64) -> FILETIME737 fn time_to_file_time(sec: i64) -> FILETIME { 738 let t = (((sec * HECTONANOSECS_IN_SEC) + HECTONANOSEC_TO_UNIX_EPOCH)) as u64; 739 FILETIME { 740 dwLowDateTime: t as DWORD, 741 dwHighDateTime: (t >> 32) as DWORD 742 } 743 } 744 file_time_as_u64(ft: &FILETIME) -> u64745 fn file_time_as_u64(ft: &FILETIME) -> u64 { 746 ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64) 747 } 748 file_time_to_nsec(ft: &FILETIME) -> i32749 fn file_time_to_nsec(ft: &FILETIME) -> i32 { 750 let t = file_time_as_u64(ft) as i64; 751 ((t % HECTONANOSECS_IN_SEC) * 100) as i32 752 } 753 file_time_to_unix_seconds(ft: &FILETIME) -> i64754 fn file_time_to_unix_seconds(ft: &FILETIME) -> i64 { 755 let t = file_time_as_u64(ft) as i64; 756 ((t - HECTONANOSEC_TO_UNIX_EPOCH) / HECTONANOSECS_IN_SEC) as i64 757 } 758 system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME759 fn system_time_to_file_time(sys: &SYSTEMTIME) -> FILETIME { 760 unsafe { 761 let mut ft = mem::zeroed(); 762 SystemTimeToFileTime(sys, &mut ft); 763 ft 764 } 765 } 766 tm_to_system_time(tm: &Tm) -> SYSTEMTIME767 fn tm_to_system_time(tm: &Tm) -> SYSTEMTIME { 768 let mut sys: SYSTEMTIME = unsafe { mem::zeroed() }; 769 sys.wSecond = tm.tm_sec as WORD; 770 sys.wMinute = tm.tm_min as WORD; 771 sys.wHour = tm.tm_hour as WORD; 772 sys.wDay = tm.tm_mday as WORD; 773 sys.wDayOfWeek = tm.tm_wday as WORD; 774 sys.wMonth = (tm.tm_mon + 1) as WORD; 775 sys.wYear = (tm.tm_year + 1900) as WORD; 776 sys 777 } 778 system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm)779 fn system_time_to_tm(sys: &SYSTEMTIME, tm: &mut Tm) { 780 tm.tm_sec = sys.wSecond as i32; 781 tm.tm_min = sys.wMinute as i32; 782 tm.tm_hour = sys.wHour as i32; 783 tm.tm_mday = sys.wDay as i32; 784 tm.tm_wday = sys.wDayOfWeek as i32; 785 tm.tm_mon = (sys.wMonth - 1) as i32; 786 tm.tm_year = (sys.wYear - 1900) as i32; 787 tm.tm_yday = yday(tm.tm_year, tm.tm_mon + 1, tm.tm_mday); 788 789 fn yday(year: i32, month: i32, day: i32) -> i32 { 790 let leap = if month > 2 { 791 if year % 4 == 0 { 1 } else { 2 } 792 } else { 793 0 794 }; 795 let july = if month > 7 { 1 } else { 0 }; 796 797 (month - 1) * 30 + month / 2 + (day - 1) - leap + july 798 } 799 } 800 801 macro_rules! call { 802 ($name:ident($($arg:expr),*)) => { 803 if $name($($arg),*) == 0 { 804 panic!(concat!(stringify!($name), " failed with: {}"), 805 io::Error::last_os_error()); 806 } 807 } 808 } 809 time_to_utc_tm(sec: i64, tm: &mut Tm)810 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { 811 let mut out = unsafe { mem::zeroed() }; 812 let ft = time_to_file_time(sec); 813 unsafe { 814 call!(FileTimeToSystemTime(&ft, &mut out)); 815 } 816 system_time_to_tm(&out, tm); 817 tm.tm_utcoff = 0; 818 } 819 time_to_local_tm(sec: i64, tm: &mut Tm)820 pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { 821 let ft = time_to_file_time(sec); 822 unsafe { 823 let mut utc = mem::zeroed(); 824 let mut local = mem::zeroed(); 825 call!(FileTimeToSystemTime(&ft, &mut utc)); 826 call!(SystemTimeToTzSpecificLocalTime(0 as *const _, 827 &mut utc, &mut local)); 828 system_time_to_tm(&local, tm); 829 830 let local = system_time_to_file_time(&local); 831 let local_sec = file_time_to_unix_seconds(&local); 832 833 let mut tz = mem::zeroed(); 834 GetTimeZoneInformation(&mut tz); 835 836 // SystemTimeToTzSpecificLocalTime already applied the biases so 837 // check if it non standard 838 tm.tm_utcoff = (local_sec - sec) as i32; 839 tm.tm_isdst = if tm.tm_utcoff == -60 * (tz.Bias + tz.StandardBias) { 840 0 841 } else { 842 1 843 }; 844 } 845 } 846 utc_tm_to_time(tm: &Tm) -> i64847 pub fn utc_tm_to_time(tm: &Tm) -> i64 { 848 unsafe { 849 let mut ft = mem::zeroed(); 850 let sys_time = tm_to_system_time(tm); 851 call!(SystemTimeToFileTime(&sys_time, &mut ft)); 852 file_time_to_unix_seconds(&ft) 853 } 854 } 855 local_tm_to_time(tm: &Tm) -> i64856 pub fn local_tm_to_time(tm: &Tm) -> i64 { 857 unsafe { 858 let mut ft = mem::zeroed(); 859 let mut utc = mem::zeroed(); 860 let mut sys_time = tm_to_system_time(tm); 861 call!(TzSpecificLocalTimeToSystemTime(0 as *mut _, 862 &mut sys_time, &mut utc)); 863 call!(SystemTimeToFileTime(&utc, &mut ft)); 864 file_time_to_unix_seconds(&ft) 865 } 866 } 867 get_time() -> (i64, i32)868 pub fn get_time() -> (i64, i32) { 869 unsafe { 870 let mut ft = mem::zeroed(); 871 GetSystemTimeAsFileTime(&mut ft); 872 (file_time_to_unix_seconds(&ft), file_time_to_nsec(&ft)) 873 } 874 } 875 get_precise_ns() -> u64876 pub fn get_precise_ns() -> u64 { 877 let mut ticks = i64_to_large_integer(0); 878 unsafe { 879 assert!(QueryPerformanceCounter(&mut ticks) == 1); 880 } 881 mul_div_i64(large_integer_to_i64(ticks), 1000000000, frequency()) as u64 882 883 } 884 885 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] 886 pub struct SteadyTime { 887 t: i64, 888 } 889 890 impl SteadyTime { now() -> SteadyTime891 pub fn now() -> SteadyTime { 892 let mut l = i64_to_large_integer(0); 893 unsafe { QueryPerformanceCounter(&mut l); } 894 SteadyTime { t : large_integer_to_i64(l) } 895 } 896 } 897 898 impl Sub for SteadyTime { 899 type Output = Duration; sub(self, other: SteadyTime) -> Duration900 fn sub(self, other: SteadyTime) -> Duration { 901 let diff = self.t as i64 - other.t as i64; 902 Duration::nanoseconds(mul_div_i64(diff, 1000000000, 903 frequency())) 904 } 905 } 906 907 impl Sub<Duration> for SteadyTime { 908 type Output = SteadyTime; sub(self, other: Duration) -> SteadyTime909 fn sub(self, other: Duration) -> SteadyTime { 910 self + -other 911 } 912 } 913 914 impl Add<Duration> for SteadyTime { 915 type Output = SteadyTime; add(mut self, other: Duration) -> SteadyTime916 fn add(mut self, other: Duration) -> SteadyTime { 917 self.t += (other.num_microseconds().unwrap() * frequency() / 918 1_000_000) as i64; 919 self 920 } 921 } 922 923 #[cfg(test)] 924 pub struct TzReset { 925 old: TIME_ZONE_INFORMATION, 926 } 927 928 #[cfg(test)] 929 impl Drop for TzReset { drop(&mut self)930 fn drop(&mut self) { 931 unsafe { 932 call!(SetTimeZoneInformation(&self.old)); 933 } 934 } 935 } 936 937 #[cfg(test)] set_los_angeles_time_zone() -> TzReset938 pub fn set_los_angeles_time_zone() -> TzReset { 939 acquire_privileges(); 940 941 unsafe { 942 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 943 GetTimeZoneInformation(&mut tz); 944 let ret = TzReset { old: tz }; 945 tz.Bias = 60 * 8; 946 call!(SetTimeZoneInformation(&tz)); 947 return ret 948 } 949 } 950 951 #[cfg(test)] set_london_with_dst_time_zone() -> TzReset952 pub fn set_london_with_dst_time_zone() -> TzReset { 953 acquire_privileges(); 954 955 unsafe { 956 let mut tz = mem::zeroed::<TIME_ZONE_INFORMATION>(); 957 GetTimeZoneInformation(&mut tz); 958 let ret = TzReset { old: tz }; 959 // Since date set precisely this is 2015's dates 960 tz.Bias = 0; 961 tz.DaylightBias = -60; 962 tz.DaylightDate.wYear = 0; 963 tz.DaylightDate.wMonth = 3; 964 tz.DaylightDate.wDayOfWeek = 0; 965 tz.DaylightDate.wDay = 5; 966 tz.DaylightDate.wHour = 2; 967 tz.StandardBias = 0; 968 tz.StandardDate.wYear = 0; 969 tz.StandardDate.wMonth = 10; 970 tz.StandardDate.wDayOfWeek = 0; 971 tz.StandardDate.wDay = 5; 972 tz.StandardDate.wHour = 2; 973 call!(SetTimeZoneInformation(&tz)); 974 return ret 975 } 976 } 977 978 // Ensures that this process has the necessary privileges to set a new time 979 // zone, and this is all transcribed from: 980 // https://msdn.microsoft.com/en-us/library/windows/desktop/ms724944%28v=vs.85%29.aspx 981 #[cfg(test)] acquire_privileges()982 fn acquire_privileges() { 983 use std::sync::{ONCE_INIT, Once}; 984 use winapi::um::processthreadsapi::*; 985 use winapi::um::winbase::LookupPrivilegeValueA; 986 const SE_PRIVILEGE_ENABLED: DWORD = 2; 987 static INIT: Once = ONCE_INIT; 988 989 // TODO: FIXME 990 extern "system" { 991 fn AdjustTokenPrivileges( 992 TokenHandle: HANDLE, DisableAllPrivileges: BOOL, NewState: PTOKEN_PRIVILEGES, 993 BufferLength: DWORD, PreviousState: PTOKEN_PRIVILEGES, ReturnLength: PDWORD, 994 ) -> BOOL; 995 } 996 997 #[repr(C)] 998 struct TKP { 999 tkp: TOKEN_PRIVILEGES, 1000 laa: LUID_AND_ATTRIBUTES, 1001 } 1002 1003 INIT.call_once(|| unsafe { 1004 let mut hToken = 0 as *mut _; 1005 call!(OpenProcessToken(GetCurrentProcess(), 1006 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 1007 &mut hToken)); 1008 1009 let mut tkp = mem::zeroed::<TKP>(); 1010 assert_eq!(tkp.tkp.Privileges.len(), 0); 1011 let c = ::std::ffi::CString::new("SeTimeZonePrivilege").unwrap(); 1012 call!(LookupPrivilegeValueA(0 as *const _, c.as_ptr(), 1013 &mut tkp.laa.Luid)); 1014 tkp.tkp.PrivilegeCount = 1; 1015 tkp.laa.Attributes = SE_PRIVILEGE_ENABLED; 1016 call!(AdjustTokenPrivileges(hToken, FALSE, &mut tkp.tkp, 0, 1017 0 as *mut _, 0 as *mut _)); 1018 }); 1019 } 1020 1021 1022 1023 // Computes (value*numer)/denom without overflow, as long as both 1024 // (numer*denom) and the overall result fit into i64 (which is the case 1025 // for our time conversions). mul_div_i64(value: i64, numer: i64, denom: i64) -> i641026 fn mul_div_i64(value: i64, numer: i64, denom: i64) -> i64 { 1027 let q = value / denom; 1028 let r = value % denom; 1029 // Decompose value as (value/denom*denom + value%denom), 1030 // substitute into (value*numer)/denom and simplify. 1031 // r < denom, so (denom*numer) is the upper bound of (r*numer) 1032 q * numer + r * numer / denom 1033 } 1034 1035 #[test] test_muldiv()1036 fn test_muldiv() { 1037 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000, 1_000_000), 1038 1_000_000_000_001_000); 1039 assert_eq!(mul_div_i64(-1_000_000_000_001, 1_000_000_000, 1_000_000), 1040 -1_000_000_000_001_000); 1041 assert_eq!(mul_div_i64(-1_000_000_000_001,-1_000_000_000, 1_000_000), 1042 1_000_000_000_001_000); 1043 assert_eq!(mul_div_i64( 1_000_000_000_001, 1_000_000_000,-1_000_000), 1044 -1_000_000_000_001_000); 1045 assert_eq!(mul_div_i64( 1_000_000_000_001,-1_000_000_000,-1_000_000), 1046 1_000_000_000_001_000); 1047 } 1048 } 1049