cyclonedx_bom/external_models/
date_time.rs1use std::convert::TryFrom;
20
21use thiserror::Error;
22use time::{format_description::well_known::Iso8601, OffsetDateTime};
23
24use crate::validation::ValidationError;
25
26#[derive(Clone, Debug, PartialEq, Eq, Hash)]
42pub struct DateTime(pub(crate) String);
43
44pub fn validate_date_time(date_time: &DateTime) -> Result<(), ValidationError> {
45 if OffsetDateTime::parse(&date_time.0, &Iso8601::DEFAULT).is_err() {
46 return Err("DateTime does not conform to ISO 8601".into());
47 }
48 Ok(())
49}
50
51impl DateTime {
52 pub fn now() -> Result<Self, DateTimeError> {
53 let now = OffsetDateTime::now_utc()
54 .format(&Iso8601::DEFAULT)
55 .map_err(|_| DateTimeError::FailedCurrentTime)?;
56 Ok(Self(now))
57 }
58}
59
60impl TryFrom<String> for DateTime {
61 type Error = DateTimeError;
62
63 fn try_from(value: String) -> Result<Self, Self::Error> {
64 match OffsetDateTime::parse(&value, &Iso8601::DEFAULT) {
65 Ok(_) => Ok(Self(value)),
66 Err(e) => Err(DateTimeError::InvalidDateTime(format!(
67 "DateTime does not conform to ISO 8601: {}",
68 e
69 ))),
70 }
71 }
72}
73
74impl std::fmt::Display for DateTime {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 f.write_str(&self.0)
77 }
78}
79
80impl AsRef<str> for DateTime {
81 fn as_ref(&self) -> &str {
82 &self.0
83 }
84}
85
86#[derive(Debug, Error, PartialEq, Eq)]
87pub enum DateTimeError {
88 #[error("Invalid DateTime: {}", .0)]
89 InvalidDateTime(String),
90
91 #[error("Failed to get current time")]
92 FailedCurrentTime,
93}
94
95#[cfg(test)]
96mod test {
97 use pretty_assertions::assert_eq;
98
99 use crate::{external_models::validate_date_time, prelude::DateTime};
100
101 #[test]
102 fn valid_datetimes_should_pass_validation() {
103 let validation_result =
104 validate_date_time(&DateTime("1969-06-28T01:20:00.00-04:00".to_string()));
105
106 assert!(validation_result.is_ok());
107 }
108
109 #[test]
110 fn invalid_datetimes_should_fail_validation() {
111 let validation_result = validate_date_time(&DateTime("invalid date".to_string()));
112
113 assert_eq!(
114 validation_result,
115 Err("DateTime does not conform to ISO 8601".into()),
116 );
117 }
118}