Skip to main content

midenc_log/fmt/
humantime.rs

1use std::{fmt, time::SystemTime};
2
3use crate::fmt::{Formatter, TimestampPrecision};
4
5impl Formatter {
6    /// Get a [`Timestamp`] for the current date and time in UTC.
7    ///
8    /// # Examples
9    ///
10    /// Include the current timestamp with the log record:
11    ///
12    /// ```
13    /// use std::io::Write;
14    ///
15    /// let mut builder = midenc_log::Builder::new();
16    ///
17    /// builder.format(|buf, record| {
18    ///     let ts = buf.timestamp();
19    ///
20    ///     writeln!(buf, "{}: {}: {}", ts, record.level(), record.args())
21    /// });
22    /// ```
23    pub fn timestamp(&self) -> Timestamp {
24        Timestamp {
25            time: SystemTime::now(),
26            precision: TimestampPrecision::Seconds,
27        }
28    }
29
30    /// Get a [`Timestamp`] for the current date and time in UTC with full
31    /// second precision.
32    pub fn timestamp_seconds(&self) -> Timestamp {
33        Timestamp {
34            time: SystemTime::now(),
35            precision: TimestampPrecision::Seconds,
36        }
37    }
38
39    /// Get a [`Timestamp`] for the current date and time in UTC with
40    /// millisecond precision.
41    pub fn timestamp_millis(&self) -> Timestamp {
42        Timestamp {
43            time: SystemTime::now(),
44            precision: TimestampPrecision::Millis,
45        }
46    }
47
48    /// Get a [`Timestamp`] for the current date and time in UTC with
49    /// microsecond precision.
50    pub fn timestamp_micros(&self) -> Timestamp {
51        Timestamp {
52            time: SystemTime::now(),
53            precision: TimestampPrecision::Micros,
54        }
55    }
56
57    /// Get a [`Timestamp`] for the current date and time in UTC with
58    /// nanosecond precision.
59    pub fn timestamp_nanos(&self) -> Timestamp {
60        Timestamp {
61            time: SystemTime::now(),
62            precision: TimestampPrecision::Nanos,
63        }
64    }
65}
66
67/// An [RFC3339] formatted timestamp.
68///
69/// The timestamp implements [`Display`] and can be written to a [`Formatter`].
70///
71/// [RFC3339]: https://www.ietf.org/rfc/rfc3339.txt
72/// [`Display`]: std::fmt::Display
73pub struct Timestamp {
74    time: SystemTime,
75    precision: TimestampPrecision,
76}
77
78impl fmt::Debug for Timestamp {
79    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80        /// A `Debug` wrapper for `Timestamp` that uses the `Display` implementation.
81        struct TimestampValue<'a>(&'a Timestamp);
82
83        impl fmt::Debug for TimestampValue<'_> {
84            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85                fmt::Display::fmt(&self.0, f)
86            }
87        }
88
89        f.debug_tuple("Timestamp").field(&TimestampValue(self)).finish()
90    }
91}
92
93impl fmt::Display for Timestamp {
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        let Ok(ts) = jiff::Timestamp::try_from(self.time) else {
96            return Err(fmt::Error);
97        };
98
99        match self.precision {
100            TimestampPrecision::Seconds => write!(f, "{ts:.0}"),
101            TimestampPrecision::Millis => write!(f, "{ts:.3}"),
102            TimestampPrecision::Micros => write!(f, "{ts:.6}"),
103            TimestampPrecision::Nanos => write!(f, "{ts:.9}"),
104        }
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::Timestamp;
111    use crate::TimestampPrecision;
112
113    #[test]
114    fn test_display_timestamp() {
115        let mut ts = Timestamp {
116            time: std::time::SystemTime::UNIX_EPOCH,
117            precision: TimestampPrecision::Nanos,
118        };
119
120        assert_eq!("1970-01-01T00:00:00.000000000Z", format!("{ts}"));
121
122        ts.precision = TimestampPrecision::Micros;
123        assert_eq!("1970-01-01T00:00:00.000000Z", format!("{ts}"));
124
125        ts.precision = TimestampPrecision::Millis;
126        assert_eq!("1970-01-01T00:00:00.000Z", format!("{ts}"));
127
128        ts.precision = TimestampPrecision::Seconds;
129        assert_eq!("1970-01-01T00:00:00Z", format!("{ts}"));
130    }
131}