Skip to main content

canic_backup/timestamp/
mod.rs

1//! Module: timestamp
2//!
3//! Responsibility: derive and generate compact unix timestamp markers for backup metadata.
4//! Does not own: clock synchronization, ordering guarantees, or persistence.
5//! Boundary: supplies human-readable timestamps to backup journals and reports.
6
7use std::time::{SystemTime, UNIX_EPOCH};
8
9/// Return the current wall-clock timestamp as a compact unix-seconds marker.
10#[must_use]
11pub fn current_timestamp_marker() -> String {
12    timestamp_marker(current_unix_seconds())
13}
14
15pub(crate) fn state_updated_at(updated_at: Option<&String>) -> String {
16    updated_at.cloned().unwrap_or_else(current_timestamp_marker)
17}
18
19pub(crate) fn timestamp_seconds(marker: &str) -> u64 {
20    marker
21        .strip_prefix("unix:")
22        .and_then(|seconds| seconds.parse::<u64>().ok())
23        .unwrap_or_else(current_unix_seconds)
24}
25
26pub(crate) fn timestamp_marker(seconds: u64) -> String {
27    format!("unix:{seconds}")
28}
29
30fn current_unix_seconds() -> u64 {
31    SystemTime::now()
32        .duration_since(UNIX_EPOCH)
33        .map_or(0, |duration| duration.as_secs())
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39
40    // Ensure generated timestamp markers use the stable unix-seconds prefix.
41    #[test]
42    fn current_timestamp_marker_uses_unix_prefix() {
43        let marker = current_timestamp_marker();
44        let seconds = marker
45            .strip_prefix("unix:")
46            .expect("timestamp marker should include prefix");
47
48        assert!(seconds.parse::<u64>().is_ok());
49    }
50
51    #[test]
52    fn supplied_state_timestamp_is_preserved() {
53        assert_eq!(state_updated_at(Some(&"unix:42".to_string())), "unix:42");
54        assert_eq!(timestamp_seconds("unix:42"), 42);
55        assert_eq!(timestamp_marker(42), "unix:42");
56    }
57}