]> git.proxmox.com Git - rustc.git/blob - vendor/time/src/sys.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / vendor / time / src / sys.rs
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
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
57 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
83 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
84 time_to_tm(sec, tm);
85 }
86
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
92 pub fn utc_tm_to_time(tm: &Tm) -> i64 {
93 tm_to_time(tm)
94 }
95
96 pub fn local_tm_to_time(tm: &Tm) -> i64 {
97 // FIXME: Add timezone logic
98 tm_to_time(tm)
99 }
100
101 pub fn get_time() -> (i64, i32) {
102 unimplemented!()
103 }
104
105 pub fn get_precise_ns() -> u64 {
106 unimplemented!()
107 }
108
109 impl SteadyTime {
110 pub fn now() -> SteadyTime {
111 unimplemented!()
112 }
113 }
114
115 impl Sub for SteadyTime {
116 type Output = Duration;
117 fn sub(self, _other: SteadyTime) -> Duration {
118 unimplemented!()
119 }
120 }
121
122 impl Sub<Duration> for SteadyTime {
123 type Output = SteadyTime;
124 fn sub(self, _other: Duration) -> SteadyTime {
125 unimplemented!()
126 }
127 }
128
129 impl Add<Duration> for SteadyTime {
130 type Output = SteadyTime;
131 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
148 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
149 time_to_tm(sec, tm);
150 }
151
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
157 pub fn utc_tm_to_time(tm: &Tm) -> i64 {
158 tm_to_time(tm)
159 }
160
161 pub fn local_tm_to_time(tm: &Tm) -> i64 {
162 // FIXME: Add timezone logic
163 tm_to_time(tm)
164 }
165
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
172 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 {
184 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 {
191 fn clone(&self) -> SteadyTime {
192 SteadyTime { t: self.t }
193 }
194 }
195
196 impl SteadyTime {
197 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;
211 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;
225 fn sub(self, other: Duration) -> SteadyTime {
226 self + -other
227 }
228 }
229
230 impl Add<Duration> for SteadyTime {
231 type Output = SteadyTime;
232 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 {
250 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> {
251 Some(self.cmp(other))
252 }
253 }
254
255 impl Ord for SteadyTime {
256 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 {
265 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
290 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
291 time_to_tm(sec, tm);
292 }
293
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
299 pub fn utc_tm_to_time(tm: &Tm) -> i64 {
300 tm_to_time(tm)
301 }
302
303 pub fn local_tm_to_time(tm: &Tm) -> i64 {
304 // FIXME: Add timezone logic
305 tm_to_time(tm)
306 }
307
308 pub fn get_time() -> (i64, i32) {
309 SteadyTime::now().t.raw()
310 }
311
312 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 {
319 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;
330 fn sub(self, other: SteadyTime) -> Duration {
331 self.t - other.t
332 }
333 }
334
335 impl Sub<Duration> for SteadyTime {
336 type Output = SteadyTime;
337 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;
344 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
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
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"))]
394 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
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
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
455 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
466 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
479 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
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]
502 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 {
514 pub fn now() -> SteadyTime {
515 SteadyTime { t: get_precise_ns() }
516 }
517 }
518 impl Sub for SteadyTime {
519 type Output = Duration;
520 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;
526 fn sub(self, other: Duration) -> SteadyTime {
527 self + -other
528 }
529 }
530 impl Add<Duration> for SteadyTime {
531 type Output = SteadyTime;
532 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)]
545 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)]
553 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
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
575 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 {
589 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 {
596 fn clone(&self) -> SteadyTime {
597 SteadyTime { t: self.t }
598 }
599 }
600
601 impl SteadyTime {
602 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;
619 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;
633 fn sub(self, other: Duration) -> SteadyTime {
634 self + -other
635 }
636 }
637
638 impl Add<Duration> for SteadyTime {
639 type Output = SteadyTime;
640 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 {
664 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> {
665 Some(self.cmp(other))
666 }
667 }
668
669 impl Ord for SteadyTime {
670 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 {
679 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
706 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
720 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
728 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
737 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
745 fn file_time_as_u64(ft: &FILETIME) -> u64 {
746 ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64)
747 }
748
749 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
754 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
759 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
767 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
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
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
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
847 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
856 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
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
876 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 {
891 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;
900 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;
909 fn sub(self, other: Duration) -> SteadyTime {
910 self + -other
911 }
912 }
913
914 impl Add<Duration> for SteadyTime {
915 type Output = SteadyTime;
916 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 {
930 fn drop(&mut self) {
931 unsafe {
932 call!(SetTimeZoneInformation(&self.old));
933 }
934 }
935 }
936
937 #[cfg(test)]
938 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)]
952 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)]
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).
1026 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]
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 }