1use crate::Result;
8use serde::{Deserialize, Serialize};
9use std::fmt;
10use time::{
11 format_description::{
12 self,
13 well_known::{Rfc2822, Rfc3339},
14 },
15 Date, Month, OffsetDateTime, Time, UtcOffset,
16};
17use time_tz::{OffsetDateTimeExt, TimeZone};
18
19#[derive(
21 Debug, Clone, Serialize, Deserialize, Ord, PartialOrd, Eq, PartialEq,
22)]
23pub struct UtcDateTime(
24 #[serde(with = "time::serde::rfc3339")] pub(crate) OffsetDateTime,
25);
26
27impl Default for UtcDateTime {
28 fn default() -> Self {
29 Self(OffsetDateTime::now_utc())
30 }
31}
32
33impl UtcDateTime {
34 pub fn now() -> Self {
36 Default::default()
37 }
38
39 pub fn to_timezone<T: TimeZone>(&self, tz: &T) -> Self {
41 Self(self.clone().0.to_timezone(tz))
42 }
43
44 pub fn from_calendar_date(
46 year: i32,
47 month: Month,
48 day: u8,
49 ) -> Result<Self> {
50 let date = Date::from_calendar_date(year, month, day)?;
51 let offset_date_time = OffsetDateTime::now_utc();
52 let offset_date_time = offset_date_time.replace_date(date);
53 let offset_date_time = offset_date_time.replace_time(Time::MIDNIGHT);
54 Ok(Self(offset_date_time))
55 }
56
57 pub fn parse_simple_date(s: &str) -> Result<Self> {
59 let date_separator =
60 format_description::parse("[year]-[month]-[day]")?;
61 let date = Date::parse(s, &date_separator)?;
62 let offset_date_time = OffsetDateTime::now_utc();
63 let offset_date_time = offset_date_time.replace_date(date);
64 let offset_date_time = offset_date_time.replace_time(Time::MIDNIGHT);
65 Ok(Self(offset_date_time))
66 }
67
68 pub fn format_simple_date(&self) -> Result<String> {
70 let format = format_description::parse("[year]-[month]-[day]")?;
71 Ok(self.0.format(&format)?)
72 }
73
74 pub fn format(&self, description: &str) -> Result<String> {
76 let format = format_description::parse(description)?;
77 Ok(self.0.format(&format)?)
78 }
79
80 pub fn parse_rfc3339(value: &str) -> Result<Self> {
82 Ok(Self(OffsetDateTime::parse(value, &Rfc3339)?))
83 }
84
85 pub fn to_date_time(&self) -> Result<String> {
88 let format = format_description::parse(
89 "[day] [month repr:short] [year] [hour]:[minute]:[second]",
90 )?;
91 Ok(self.0.format(&format)?)
92 }
93
94 pub fn to_rfc2822(&self) -> Result<String> {
96 UtcDateTime::rfc2822(&self.0)
97 }
98
99 fn rfc2822(datetime: &OffsetDateTime) -> Result<String> {
101 Ok(datetime.format(&Rfc2822)?)
102 }
103
104 pub fn to_rfc3339(&self) -> Result<String> {
106 UtcDateTime::rfc3339(&self.0)
107 }
108
109 pub fn rfc3339(datetime: &OffsetDateTime) -> Result<String> {
111 Ok(datetime.format(&Rfc3339)?)
112 }
113
114 pub fn into_date(self) -> Date {
116 self.0.date()
117 }
118
119 pub fn into_time(self) -> Time {
121 self.0.time()
122 }
123}
124
125impl fmt::Display for UtcDateTime {
126 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match UtcOffset::current_local_offset() {
128 Ok(local_offset) => {
129 let datetime = self.0;
130 datetime.to_offset(local_offset);
131 match UtcDateTime::rfc2822(&datetime) {
132 Ok(value) => {
133 write!(f, "{}", value)
134 }
135 Err(_) => {
136 write!(f, "{}", datetime)
137 }
138 }
139 }
140 Err(_) => match self.to_rfc2822() {
141 Ok(value) => {
142 write!(f, "{}", value)
143 }
144 Err(_) => {
145 write!(f, "{}", self.0)
146 }
147 },
148 }
149 }
150}
151
152impl From<OffsetDateTime> for UtcDateTime {
153 fn from(value: OffsetDateTime) -> Self {
154 Self(value)
155 }
156}
157
158impl From<UtcDateTime> for OffsetDateTime {
159 fn from(value: UtcDateTime) -> Self {
160 value.0
161 }
162}