dynomite/util/time.rs
1//! Wall-clock and digit-counting helpers.
2//!
3//! The C reference exposes `dn_msec_now`, `dn_usec_now`,
4//! `current_timestamp_in_millis`, and `count_digits`. This module
5//! gathers them as plain functions over `std::time::SystemTime`.
6
7use std::time::{SystemTime, UNIX_EPOCH};
8
9use crate::core::types::{Msec, Usec};
10
11/// Microseconds since the UNIX epoch.
12///
13/// Returns zero if the system clock reports a time before the epoch.
14///
15/// # Examples
16///
17/// ```
18/// use dynomite::util::time::usec_now;
19/// assert!(usec_now() > 0);
20/// ```
21pub fn usec_now() -> Usec {
22 SystemTime::now()
23 .duration_since(UNIX_EPOCH)
24 .map(|d| {
25 let micros = d.as_micros();
26 if micros > u128::from(Usec::MAX) {
27 Usec::MAX
28 } else {
29 #[allow(clippy::cast_possible_truncation)]
30 {
31 micros as Usec
32 }
33 }
34 })
35 .unwrap_or(0)
36}
37
38/// Milliseconds since the UNIX epoch.
39///
40/// # Examples
41///
42/// ```
43/// use dynomite::util::time::msec_now;
44/// let a = msec_now();
45/// let b = msec_now();
46/// assert!(b >= a);
47/// ```
48pub fn msec_now() -> Msec {
49 usec_now() / 1000
50}
51
52/// Number of decimal digits in `arg`, including a leading zero.
53///
54/// # Examples
55///
56/// ```
57/// use dynomite::util::time::count_digits;
58/// assert_eq!(count_digits(0), 1);
59/// assert_eq!(count_digits(9), 1);
60/// assert_eq!(count_digits(10), 2);
61/// assert_eq!(count_digits(u64::MAX), 20);
62/// ```
63pub fn count_digits(arg: u64) -> u32 {
64 if arg == 0 {
65 1
66 } else {
67 arg.ilog10() + 1
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn msec_is_monotone_non_decreasing() {
77 let a = msec_now();
78 for _ in 0..16 {
79 let b = msec_now();
80 assert!(b >= a);
81 }
82 }
83
84 #[test]
85 fn msec_is_within_usec_to_msec_factor() {
86 let m = msec_now();
87 let u = usec_now();
88 // The two readings happen back-to-back; allow a few ms of skew.
89 assert!(u / 1000 >= m);
90 assert!(u / 1000 <= m + 50);
91 }
92
93 #[test]
94 fn digit_table_matches_ten_powers() {
95 for d in 1u32..=18 {
96 let n = 10u64.pow(d);
97 assert_eq!(count_digits(n), d + 1);
98 assert_eq!(count_digits(n - 1), d);
99 }
100 }
101}