]> git.proxmox.com Git - rustc.git/blob - vendor/time/src/sys.rs
New upstream version 1.52.0~beta.3+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_env = "sgx"
8 ))]
9 mod common {
10 use Tm;
11
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
56 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
82 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
83 time_to_tm(sec, tm);
84 }
85
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
91 pub fn utc_tm_to_time(tm: &Tm) -> i64 {
92 tm_to_time(tm)
93 }
94
95 pub fn local_tm_to_time(tm: &Tm) -> i64 {
96 // FIXME: Add timezone logic
97 tm_to_time(tm)
98 }
99
100 pub fn get_time() -> (i64, i32) {
101 unimplemented!()
102 }
103
104 pub fn get_precise_ns() -> u64 {
105 unimplemented!()
106 }
107
108 impl SteadyTime {
109 pub fn now() -> SteadyTime {
110 unimplemented!()
111 }
112 }
113
114 impl Sub for SteadyTime {
115 type Output = Duration;
116 fn sub(self, _other: SteadyTime) -> Duration {
117 unimplemented!()
118 }
119 }
120
121 impl Sub<Duration> for SteadyTime {
122 type Output = SteadyTime;
123 fn sub(self, _other: Duration) -> SteadyTime {
124 unimplemented!()
125 }
126 }
127
128 impl Add<Duration> for SteadyTime {
129 type Output = SteadyTime;
130 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
152 pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) {
153 time_to_tm(sec, tm);
154 }
155
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
161 pub fn utc_tm_to_time(tm: &Tm) -> i64 {
162 tm_to_time(tm)
163 }
164
165 pub fn local_tm_to_time(tm: &Tm) -> i64 {
166 // FIXME: Add timezone logic
167 tm_to_time(tm)
168 }
169
170 pub fn get_time() -> (i64, i32) {
171 SteadyTime::now().t.raw()
172 }
173
174 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 {
182 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;
194 fn sub(self, other: SteadyTime) -> Duration {
195 self.t - other.t
196 }
197 }
198
199 impl Sub<Duration> for SteadyTime {
200 type Output = SteadyTime;
201 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;
208 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
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
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"))]
258 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
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
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
319 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
335 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)]
351 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
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]
375 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 {
387 pub fn now() -> SteadyTime {
388 SteadyTime { t: get_precise_ns() }
389 }
390 }
391 impl Sub for SteadyTime {
392 type Output = Duration;
393 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;
399 fn sub(self, other: Duration) -> SteadyTime {
400 self + -other
401 }
402 }
403 impl Add<Duration> for SteadyTime {
404 type Output = SteadyTime;
405 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)]
418 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)]
426 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
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
448 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 {
462 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 {
469 fn clone(&self) -> SteadyTime {
470 SteadyTime { t: self.t }
471 }
472 }
473
474 impl SteadyTime {
475 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;
492 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;
506 fn sub(self, other: Duration) -> SteadyTime {
507 self + -other
508 }
509 }
510
511 impl Add<Duration> for SteadyTime {
512 type Output = SteadyTime;
513 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 {
537 fn partial_cmp(&self, other: &SteadyTime) -> Option<Ordering> {
538 Some(self.cmp(other))
539 }
540 }
541
542 impl Ord for SteadyTime {
543 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 {
552 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
580 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
595 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
603 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
612 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
620 fn file_time_as_u64(ft: &FILETIME) -> u64 {
621 ((ft.dwHighDateTime as u64) << 32) | (ft.dwLowDateTime as u64)
622 }
623
624 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
629 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
634 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
642 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
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
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
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
722 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
731 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
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
751 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 {
766 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;
775 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;
784 fn sub(self, other: Duration) -> SteadyTime {
785 self + -other
786 }
787 }
788
789 impl Add<Duration> for SteadyTime {
790 type Output = SteadyTime;
791 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 {
805 fn drop(&mut self) {
806 unsafe {
807 call!(SetTimeZoneInformation(&self.old));
808 }
809 }
810 }
811
812 #[cfg(test)]
813 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)]
827 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)]
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).
895 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]
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 }