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