1 //
2 // Copyright 2023 Google, Inc.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at:
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15
16 //! # Time Display class
17
18 use std::time::{SystemTime, UNIX_EPOCH};
19
20 use chrono::{DateTime, Datelike, NaiveDateTime, Timelike, Utc};
21
22 /// A simple class that contains information required to display time
23 pub struct TimeDisplay {
24 /// seconds since std::time::UNIX_EPOCH
25 secs: i64,
26 /// nano sub seconds since std::time::UNIX_EPOCH
27 nsecs: u32,
28 }
29
30 impl TimeDisplay {
31 /// Creates a new TimeDisplay with given secs and nsecs
32 ///
33 /// # Arguments
34 ///
35 /// * `secs` - seconds since std::time::UNIX_EPOCH
36 /// * `nsecs` - nano sub seconds since std::time::UNIX_EPOCH
new(secs: i64, nsecs: u32) -> TimeDisplay37 pub fn new(secs: i64, nsecs: u32) -> TimeDisplay {
38 TimeDisplay { secs, nsecs }
39 }
40
41 /// Displays date & time in UTC with a format YYYY-MM-DD-HH:MM:SS
42 ///
43 /// # Returns
44 ///
45 /// `String` display of utc time.
utc_display(&self) -> String46 pub fn utc_display(&self) -> String {
47 if let Some(datetime) = NaiveDateTime::from_timestamp_opt(self.secs, self.nsecs) {
48 let current_datetime = DateTime::<Utc>::from_naive_utc_and_offset(datetime, Utc);
49 return format!(
50 "{}-{:02}-{:02}-{:02}-{:02}-{:02}",
51 current_datetime.year(),
52 current_datetime.month(),
53 current_datetime.day(),
54 current_datetime.hour(),
55 current_datetime.minute(),
56 current_datetime.second()
57 );
58 }
59 "INVALID-TIMESTAMP".to_string()
60 }
61
62 /// Displays time in UTC without date with a format HH:MM:SS
63 ///
64 /// # Returns
65 ///
66 /// `Ok(String)` if the display was successful, `Error` otherwise.
utc_display_hms(&self) -> String67 pub fn utc_display_hms(&self) -> String {
68 if let Some(datetime) = NaiveDateTime::from_timestamp_opt(self.secs, self.nsecs) {
69 let current_datetime = DateTime::<Utc>::from_naive_utc_and_offset(datetime, Utc);
70 return format!(
71 "{:02}:{:02}:{:02}",
72 current_datetime.hour(),
73 current_datetime.minute(),
74 current_datetime.second()
75 );
76 }
77 "INVALID".to_string()
78 }
79
80 /// Displays time in UTC for logs
utc_display_log(&self) -> String81 fn utc_display_log(&self) -> String {
82 if let Some(datetime) = NaiveDateTime::from_timestamp_opt(self.secs, self.nsecs) {
83 let current_datetime = DateTime::<Utc>::from_naive_utc_and_offset(datetime, Utc);
84 return format!(
85 "{:02}-{:02} {:02}:{:02}:{:02}.{:.3}",
86 current_datetime.month(),
87 current_datetime.day(),
88 current_datetime.hour(),
89 current_datetime.minute(),
90 current_datetime.second(),
91 current_datetime.timestamp_subsec_nanos().to_string(),
92 );
93 }
94 "INVALID-TIMESTAMP".to_string()
95 }
96 }
97
98 // Get TimeDisplay of current_time
get_current_time() -> TimeDisplay99 fn get_current_time() -> TimeDisplay {
100 let since_epoch = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time went backwards");
101 TimeDisplay::new(since_epoch.as_secs() as i64, since_epoch.subsec_nanos())
102 }
103
104 /// Return the timestamp of the current time for logs
log_current_time() -> String105 pub fn log_current_time() -> String {
106 get_current_time().utc_display_log()
107 }
108
109 /// Return the timestamp of the current time for files
file_current_time() -> String110 pub fn file_current_time() -> String {
111 get_current_time().utc_display()
112 }
113
114 #[cfg(test)]
115 mod tests {
116
117 use super::TimeDisplay;
118
119 #[test]
test_utc_display_ok()120 fn test_utc_display_ok() {
121 let epoch_time = TimeDisplay::new(0, 0);
122 let utc_epoch = epoch_time.utc_display();
123 assert_eq!(utc_epoch, "1970-01-01-00-00-00");
124 let twok_time = TimeDisplay::new(946684900, 0);
125 let utc_twok = twok_time.utc_display();
126 assert_eq!(utc_twok, "2000-01-01-00-01-40");
127 }
128
129 #[test]
test_utc_display_err()130 fn test_utc_display_err() {
131 let max_seconds = TimeDisplay::new(i64::MAX, 0);
132 assert_eq!("INVALID-TIMESTAMP", max_seconds.utc_display());
133 let max_nanos = TimeDisplay::new(0, 2_000_000_000);
134 assert_eq!("INVALID-TIMESTAMP", max_nanos.utc_display());
135 }
136
137 #[test]
test_utc_display_hms()138 fn test_utc_display_hms() {
139 let epoch_time = TimeDisplay::new(0, 0);
140 let utc_epoch = epoch_time.utc_display_hms();
141 assert_eq!(utc_epoch, "00:00:00");
142 let twok_time = TimeDisplay::new(946684900, 0);
143 let utc_twok = twok_time.utc_display_hms();
144 assert_eq!(utc_twok, "00:01:40");
145 }
146
147 #[test]
test_utc_display_log()148 fn test_utc_display_log() {
149 let epoch_time = TimeDisplay::new(0, 0);
150 let utc_epoch = epoch_time.utc_display_log();
151 assert_eq!(utc_epoch, "01-01 00:00:00.0");
152 let twok_time = TimeDisplay::new(946684900, 200);
153 let utc_twok = twok_time.utc_display_log();
154 assert_eq!(utc_twok, "01-01 00:01:40.200");
155 }
156 }
157