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