1use std::time::Duration;
16use std::time::SystemTime;
17use std::time::UNIX_EPOCH;
18
19use anyhow::anyhow;
20use anyhow::bail;
21use anyhow::Result;
22
23use crate::dateutil;
24use crate::util;
25
26const MISSING_SAMPLE_WARN_DURATION_S: u64 = 60;
27
28pub fn system_time_from_date(date: &str) -> Result<SystemTime> {
30 Ok(UNIX_EPOCH
31 + Duration::from_secs(
32 dateutil::HgTime::parse(date)
33 .ok_or_else(|| {
34 anyhow!(
35 "Unrecognized timestamp format\n\
36 Input: {}.\n\
37 Examples:\n\t\
38 Keywords: now, today, yesterday\n\t\
39 Relative: \"{{humantime}} ago\", e.g. 2 days 3 hr 15m 10sec ago\n\t\
40 Relative short: Mixed {{time_digit}}{{time_unit_char}}. E.g. 10m, 3d2H, 5h30s, 10m5h\n\t\
41 Absolute: \"Jan 01 23:59\", \"01/01/1970 11:59PM\", \"1970-01-01 23:59:59\"\n\t\
42 Unix Epoch: 1589808367",
43 &date
44 )
45 })?
46 .unixtime,
47 ))
48}
49
50pub fn system_time_from_date_and_adjuster(
54 date: &str,
55 days_adjuster: Option<&str>,
56) -> Result<SystemTime> {
57 let mut time = system_time_from_date(date)?;
58 if let Some(days) = days_adjuster {
59 if days.is_empty() || days.find(|c: char| c != 'y').is_some() {
60 bail!("Unrecognized days adjuster format: {}", days);
61 }
62 let time_to_deduct = Duration::from_secs(days.chars().count() as u64 * 86400);
63 time -= time_to_deduct;
64 }
65 Ok(time)
66}
67
68pub fn system_time_range_from_date_and_adjuster(
72 start_date: &str,
73 end_date: Option<&str>,
74 duration_str: Option<&str>,
75 days_adjuster: Option<&str>,
76) -> Result<(SystemTime, SystemTime)> {
77 let start = system_time_from_date_and_adjuster(start_date, days_adjuster)?;
78 let end = match (end_date, duration_str) {
79 (Some(_), Some(_)) => {
80 bail!("--end and --duration are incompatible options")
81 }
82 (Some(end_date), None) => system_time_from_date_and_adjuster(end_date, days_adjuster)?,
83 (None, Some(duration_str)) => duration_str
84 .parse::<humantime::Duration>()
85 .ok()
86 .map(|duration: humantime::Duration| start + Into::<Duration>::into(duration))
87 .unwrap(),
88 _ => SystemTime::now(),
89 };
90
91 Ok((start, end))
92}
93
94pub fn check_initial_sample_time_with_requested_time(
97 initial_sample_time: SystemTime,
98 time_begin: SystemTime,
99) {
100 if initial_sample_time > time_begin + Duration::from_secs(MISSING_SAMPLE_WARN_DURATION_S) {
101 eprintln!(
102 "Warning: Initial sample found at {} which is over {} seconds \
103 after the requested start time of {}",
104 util::systemtime_to_datetime(initial_sample_time),
105 MISSING_SAMPLE_WARN_DURATION_S,
106 util::systemtime_to_datetime(time_begin),
107 );
108 };
109}
110
111pub fn check_initial_sample_time_in_time_range(
114 initial_sample_time: SystemTime,
115 time_begin: SystemTime,
116 time_end: SystemTime,
117) -> Result<()> {
118 if initial_sample_time > time_end {
119 bail!(
120 "No samples found in desired time range.\n\
121 Earliest sample found after {} is at {} which is after the \
122 requested end time of {}",
123 util::systemtime_to_datetime(time_begin),
124 util::systemtime_to_datetime(initial_sample_time),
125 util::systemtime_to_datetime(time_end),
126 );
127 }
128 check_initial_sample_time_with_requested_time(initial_sample_time, time_begin);
129 Ok(())
130}
131
132pub fn check_final_sample_time_with_requested_time(
135 final_sample_time: SystemTime,
136 time_end: SystemTime,
137) {
138 if final_sample_time < time_end - Duration::from_secs(MISSING_SAMPLE_WARN_DURATION_S) {
139 eprintln!(
140 "Warning: Final sample processed was for {} which is over {} \
141 seconds before the requested end time of {}",
142 util::systemtime_to_datetime(final_sample_time),
143 MISSING_SAMPLE_WARN_DURATION_S,
144 util::systemtime_to_datetime(time_end),
145 );
146 };
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_system_time_from_date_fail() {
155 if system_time_from_date("invalid").is_ok() {
156 panic!("Expected to fail but didn't")
157 }
158 }
159
160 #[test]
161 fn test_system_time_from_date_and_adjuster() {
162 assert_eq!(
163 system_time_from_date_and_adjuster("2006-02-01 13:00:30 UTC", None).unwrap(),
164 t("2006-02-01 13:00:30 UTC")
165 );
166 assert_eq!(
167 system_time_from_date_and_adjuster("2006-02-01 13:00:30 UTC", Some("y")).unwrap(),
168 t("2006-01-31 13:00:30 UTC")
169 );
170 assert_eq!(
171 system_time_from_date_and_adjuster("2006-02-01 13:00:30 UTC", Some("yy")).unwrap(),
172 t("2006-01-30 13:00:30 UTC")
173 );
174 assert_eq!(
175 system_time_from_date_and_adjuster("2006-02-01 13:00:30 UTC", Some("yyy")).unwrap(),
176 t("2006-01-29 13:00:30 UTC")
177 );
178 }
179
180 #[test]
181 fn test_system_time_from_date_and_adjuster_fail() {
182 if system_time_from_date_and_adjuster("2006-02-01 13:00:30 UTC", Some("invalid")).is_ok() {
183 panic!("Expected fo fail as adjuster is invalid")
184 }
185 }
186
187 #[test]
188 fn test_system_time_range_from_date_and_adjuster() {
189 assert_eq!(
190 system_time_range_from_date_and_adjuster(
191 "2006-02-01 13:00:30 UTC",
192 Some("2006-02-01 15:00:30 UTC"),
193 None,
194 Some("y"),
195 )
196 .unwrap(),
197 (t("2006-01-31 13:00:30 UTC"), t("2006-01-31 15:00:30 UTC"))
198 );
199 assert_eq!(
200 system_time_range_from_date_and_adjuster(
201 "2006-02-01 13:00:30 UTC",
202 None,
203 Some("10min"),
204 Some("y"),
205 )
206 .unwrap(),
207 (t("2006-01-31 13:00:30 UTC"), t("2006-01-31 13:10:30 UTC"))
208 );
209 }
210
211 fn t(h: &str) -> SystemTime {
213 system_time_from_date(h).unwrap()
214 }
215}