vault_audit_tools/utils/
time.rs1use anyhow::{Context, Result};
2use chrono::{DateTime, Utc};
3
4#[allow(dead_code)]
6pub fn parse_timestamp(ts: &str) -> Result<DateTime<Utc>> {
7 DateTime::parse_from_rfc3339(ts)
8 .context("Failed to parse timestamp")
9 .map(|dt| dt.with_timezone(&Utc))
10}
11
12#[allow(dead_code)]
14pub fn format_timestamp(dt: &DateTime<Utc>) -> String {
15 dt.format("%Y-%m-%d %H:%M:%S UTC").to_string()
16}
17
18#[allow(dead_code)]
20pub fn duration_human(start: &DateTime<Utc>, end: &DateTime<Utc>) -> String {
21 let duration = end.signed_duration_since(*start);
22 let seconds = duration.num_seconds();
23
24 if seconds < 60 {
25 format!("{} seconds", seconds)
26 } else if seconds < 3600 {
27 format!("{} minutes", seconds / 60)
28 } else if seconds < 86400 {
29 format!("{:.1} hours", seconds as f64 / 3600.0)
30 } else {
31 format!("{:.1} days", seconds as f64 / 86400.0)
32 }
33}
34
35#[cfg(test)]
36mod tests {
37 use super::*;
38 use chrono::Datelike;
39
40 #[test]
41 fn test_parse_timestamp() {
42 let ts = "2025-10-06T07:26:03.801191678Z";
43 let dt = parse_timestamp(ts).unwrap();
44 assert_eq!(dt.year(), 2025);
45 assert_eq!(dt.month(), 10);
46 assert_eq!(dt.day(), 6);
47 }
48
49 #[test]
50 fn test_duration_human() {
51 let start = parse_timestamp("2025-10-06T07:26:03Z").unwrap();
52 let end = parse_timestamp("2025-10-06T08:26:03Z").unwrap();
53 let duration = duration_human(&start, &end);
54 assert!(duration.contains("1.0 hours"));
55 }
56}