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