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