api_tools/value_objects/
datetime.rs1use chrono::{DateTime, Utc};
4use std::fmt::{Display, Formatter};
5use thiserror::Error;
6
7#[derive(Debug, Clone, PartialEq, Error)]
9pub enum UtcDateTimeError {
10 #[error("Invalid date time: {0}")]
11 InvalidDateTime(String),
12}
13
14#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Eq)]
16pub struct UtcDateTime {
17 value: DateTime<Utc>,
18}
19
20impl UtcDateTime {
21 pub fn now() -> Self {
23 Self { value: Utc::now() }
24 }
25
26 pub fn new(value: DateTime<Utc>) -> Self {
28 Self { value }
29 }
30
31 pub fn from_rfc3339(value: &str) -> Result<Self, UtcDateTimeError> {
43 let dt = DateTime::parse_from_rfc3339(value)
44 .map_err(|e| UtcDateTimeError::InvalidDateTime(format!("{e}: {value}")))?;
45
46 Ok(Self {
47 value: dt.with_timezone(&Utc),
48 })
49 }
50
51 pub fn timestamp(&self) -> i64 {
53 self.value.timestamp()
54 }
55
56 pub fn value(&self) -> DateTime<Utc> {
58 self.value
59 }
60}
61
62impl From<DateTime<Utc>> for UtcDateTime {
63 fn from(value: DateTime<Utc>) -> Self {
64 Self { value }
65 }
66}
67
68impl Display for UtcDateTime {
69 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
70 write!(f, "{}", self.value.to_rfc3339_opts(chrono::SecondsFormat::Secs, true))
71 }
72}
73
74#[cfg(test)]
75mod test {
76 use super::*;
77
78 #[test]
79 fn test_utc_date_time_display() {
80 let dt = DateTime::parse_from_rfc3339("2024-08-28T12:00:00Z")
81 .unwrap()
82 .with_timezone(&Utc);
83 let datetime = UtcDateTime::from(dt);
84
85 assert_eq!(datetime.to_string(), "2024-08-28T12:00:00Z");
86 }
87
88 #[test]
89 fn test_from_rfc3339() {
90 let datetime = UtcDateTime::from_rfc3339("2024-08-28T12:00:00Z");
91 assert!(datetime.is_ok());
92 assert_eq!(datetime.unwrap().to_string(), "2024-08-28T12:00:00Z".to_owned());
93
94 let invalid_datetime = UtcDateTime::from_rfc3339("2024-08-T12:00:00Z");
95 assert!(invalid_datetime.is_err());
96 }
97
98 #[test]
99 fn test_value() {
100 let dt = DateTime::parse_from_rfc3339("2024-08-28T12:00:00Z")
101 .unwrap()
102 .with_timezone(&Utc);
103 let datetime = UtcDateTime::from(dt);
104
105 assert_eq!(datetime.value(), dt);
106 }
107
108 #[test]
109 fn test_timestamp() {
110 let dt = DateTime::parse_from_rfc3339("2024-08-28T12:00:00Z")
111 .unwrap()
112 .with_timezone(&Utc);
113 let datetime = UtcDateTime::from(dt);
114
115 assert_eq!(datetime.timestamp(), 1724846400);
116 }
117}