//! zeitstempel is German for "timestamp". //! //! --- //! //! Time's hard. Correct time is near impossible. //! //! This crate has one purpose: give me a timestamp as an integer, coming from a monotonic clock //! source, guaranteed with or without time across suspend/hibernation of the host machine, //! and let me compare it to other timestamps. //! //! It becomes the developer's responsibility to only compare timestamps obtained from this clock source. //! Timestamps are not comparable across operating system reboots. //! //! # Why not `std::time::Instant`? //! //! [`std::time::Instant`] fulfills some of our requirements: //! //! * It's monotonic, guaranteed ([sort of][rustsource]). //! * It can be compared to other timespans. //! //! However: //! //! * It can't be serialized. //! * It's not guaranteed that the clock source it uses contains (or exclude) suspend/hibernation time across all operating systems. //! //! [rustsource]: https://doc.rust-lang.org/1.47.0/src/std/time.rs.html#213-237 //! //! # Example with suspend time //! //! ``` //! # use std::{thread, time::Duration}; //! let start = zeitstempel::now(); //! thread::sleep(Duration::from_millis(2)); //! //! let diff = Duration::from_nanos(zeitstempel::now() - start); //! assert!(diff >= Duration::from_millis(2)); //! ``` //! //! # Example with only awake time //! //! ``` //! # use std::{thread, time::Duration}; //! let start = zeitstempel::now_awake(); //! thread::sleep(Duration::from_millis(2)); //! //! let diff = Duration::from_nanos(zeitstempel::now_awake() - start); //! assert!(diff >= Duration::from_millis(2)); //! ``` //! //! # Supported operating systems //! //! We support the following operating systems: //! //! * Windows\* //! * macOS //! * Linux //! * Android //! * iOS //! //! For other operating systems there's a fallback to `std::time::Instant`, //! compared against a process-global fixed reference point. //! We don't guarantee that measured time includes time the system spends in sleep or hibernation. //! //! \* To use native Windows 10 functionality enable the `win10plus` feature. Otherwise it will use the fallback. #![deny(missing_docs)] #![deny(rustdoc::broken_intra_doc_links)] cfg_if::cfg_if! { if #[cfg(any(target_os = "macos", target_os = "ios"))] { mod mac; use mac as sys; } else if #[cfg(any(target_os = "linux", target_os = "android"))] { mod linux; use linux as sys; } else if #[cfg(all(windows, feature = "win10plus"))] { mod win10; use win10 as sys; } else if #[cfg(windows)] { mod win; use win as sys; } else { mod fallback; use fallback as sys; } } /// Returns a timestamp corresponding to "now", including suspend time. /// /// It can be compared to other timestamps gathered from this API, as long as the host was not /// rebooted inbetween. /// /// /// ## Note /// /// * The difference between two timestamps will include time the system was in sleep or /// hibernation. /// * The difference between two timestamps gathered from this is in nanoseconds. /// * The clocks on some operating systems, e.g. on Windows, are not nanosecond-precise. /// The value will still use nanosecond resolution. pub fn now() -> u64 { sys::now_including_suspend() } /// Returns a timestamp corresponding to "now", excluding suspend time. /// /// It can be compared to other timestamps gathered from this API, as long as the host was not /// rebooted inbetween. /// /// /// ## Note /// /// * The difference between two timestamps will NOT include time the system was in sleep or /// hibernation. /// * The difference between two timestamps gathered from this is in nanoseconds. /// * The clocks on some operating systems, e.g. on Windows, are not nanosecond-precise. /// The value will still use nanosecond resolution. pub fn now_awake() -> u64 { sys::now_awake() } #[cfg(test)] mod test { use super::*; use std::thread; use std::time::Duration; #[test] fn order() { let ts1 = now(); thread::sleep(Duration::from_millis(2)); let ts2 = now(); assert!(ts1 < ts2); } #[test] fn awake_time_atleast_total_time() { let ts1 = now(); let a_ts1 = now_awake(); thread::sleep(Duration::from_millis(2)); let ts2 = now(); let a_ts2 = now_awake(); assert!(ts1 < ts2); assert!(a_ts1 < a_ts2); let total_diff = Duration::from_nanos(ts2 - ts1); let awake_diff = Duration::from_nanos(a_ts2 - a_ts1); // `now_awake` gives us nanosecond resolution. That might be _too_ precise, // such that `awake` might be actually longer than `total` due to the calls taking just a // tiny bit longer. assert!( total_diff.as_millis() <= awake_diff.as_millis(), "total: {:?}, awake: {:?}", total_diff, awake_diff ); } }