Skip to main content

atlas_common/c2pa/
datetime.rs

1//! Date and time handling for C2PA manifests
2
3use crate::error::{Error, Result};
4use serde::{Deserialize, Serialize};
5use time::OffsetDateTime;
6
7/// Wrapper for OffsetDateTime with serde support and validation
8///
9/// Ensures timestamps are valid and in the correct format for C2PA manifests.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11pub struct DateTimeWrapper(#[serde(with = "time::serde::rfc3339")] pub OffsetDateTime);
12
13impl DateTimeWrapper {
14    /// Create new with current UTC time
15    ///
16    /// # Example
17    ///
18    /// ```rust
19    /// use atlas_common::c2pa::DateTimeWrapper;
20    ///
21    /// let now = DateTimeWrapper::now_utc();
22    /// println!("Current time: {}", now.to_rfc3339());
23    /// ```
24    pub fn now_utc() -> Self {
25        Self(OffsetDateTime::now_utc())
26    }
27
28    /// Validate that the datetime is reasonable
29    ///
30    /// Checks that:
31    /// - The date is after January 1, 1970
32    /// - The date is not in the future
33    ///
34    /// # Errors
35    ///
36    /// Returns an error if validation fails.
37    pub fn validate(&self) -> Result<()> {
38        if self.0.year() < 1970 {
39            return Err(Error::Time(
40                "Datetime must be after January 1, 1970".to_string(),
41            ));
42        }
43
44        let now = OffsetDateTime::now_utc();
45        if self.0 > now {
46            return Err(Error::Time("Datetime cannot be in the future".to_string()));
47        }
48
49        Ok(())
50    }
51
52    /// Get as RFC3339 string
53    ///
54    /// Returns the datetime formatted according to RFC3339 standard.
55    pub fn to_rfc3339(&self) -> String {
56        self.0
57            .format(&time::format_description::well_known::Rfc3339)
58            .unwrap_or_else(|_| self.0.to_string())
59    }
60}
61
62impl Default for DateTimeWrapper {
63    fn default() -> Self {
64        Self::now_utc()
65    }
66}
67
68impl std::fmt::Display for DateTimeWrapper {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        write!(f, "{}", self.to_rfc3339())
71    }
72}