Skip to main content

display_more/
display_unix_epoch.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::fmt;
16use std::time::Duration;
17use std::time::UNIX_EPOCH;
18
19use chrono::DateTime;
20use chrono::Utc;
21
22pub struct DisplayUnixTimeStamp {
23    /// The duration since the UNIX epoch.
24    duration: Duration,
25
26    in_millis: bool,
27
28    with_timezone: bool,
29}
30
31impl fmt::Display for DisplayUnixTimeStamp {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        let system_time = UNIX_EPOCH + self.duration;
34        let datetime: DateTime<Utc> = system_time.into();
35
36        let fmt = if self.in_millis {
37            if self.with_timezone {
38                "%Y-%m-%dT%H:%M:%S%.3fZ%z"
39            } else {
40                "%Y-%m-%dT%H:%M:%S%.3f"
41            }
42        } else if self.with_timezone {
43            "%Y-%m-%dT%H:%M:%S%.6fZ%z"
44        } else {
45            "%Y-%m-%dT%H:%M:%S%.6f"
46        };
47
48        write!(f, "{}", datetime.format(fmt))
49    }
50}
51
52impl DisplayUnixTimeStamp {
53    pub fn new(duration: Duration) -> Self {
54        Self {
55            duration,
56            in_millis: false,
57            with_timezone: true,
58        }
59    }
60
61    pub fn in_millis(self, in_millis: bool) -> Self {
62        Self { in_millis, ..self }
63    }
64
65    pub fn with_timezone(self, with_timezone: bool) -> Self {
66        Self {
67            with_timezone,
68            ..self
69        }
70    }
71}
72
73/// Implement `Display` for `Duration` to display the duration since the UNIX epoch.
74///
75/// # Example
76///
77/// ```rust
78/// use std::time::Duration;
79///
80/// use display_more::DisplayUnixTimeStampExt;
81///
82/// let duration = Duration::from_millis(1723102819023);
83/// assert_eq!(
84///     duration.display_unix_timestamp().to_string(),
85///     "2024-08-08T07:40:19.023000Z+0000"
86/// );
87/// ```
88pub trait DisplayUnixTimeStampExt {
89    fn display_unix_timestamp(&self) -> DisplayUnixTimeStamp;
90
91    /// Display the duration since the UNIX epoch in milliseconds without timezone.
92    fn display_unix_timestamp_short(&self) -> DisplayUnixTimeStamp {
93        self.display_unix_timestamp()
94            .in_millis(true)
95            .with_timezone(false)
96    }
97}
98
99impl DisplayUnixTimeStampExt for Duration {
100    fn display_unix_timestamp(&self) -> DisplayUnixTimeStamp {
101        DisplayUnixTimeStamp::new(*self)
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use std::time::Duration;
108
109    use super::*;
110
111    #[test]
112    fn test_display_unix_epoch() {
113        let epoch = Duration::from_millis(0);
114        let display = epoch.display_unix_timestamp();
115        assert_eq!(format!("{}", display), "1970-01-01T00:00:00.000000Z+0000");
116
117        let epoch = Duration::from_millis(1723102819023);
118        let display = epoch.display_unix_timestamp();
119        assert_eq!(format!("{}", display), "2024-08-08T07:40:19.023000Z+0000");
120
121        let display = epoch.display_unix_timestamp_short();
122        assert_eq!(format!("{}", display), "2024-08-08T07:40:19.023");
123    }
124}