azure_core/date/
mod.rs
1use crate::error::{ErrorKind, ResultExt};
7use std::time::Duration;
8use time::{
9 format_description::{well_known::Rfc3339, FormatItem},
10 macros::format_description,
11 OffsetDateTime, PrimitiveDateTime, UtcOffset,
12};
13
14pub use time::serde::rfc3339;
16pub use time::serde::timestamp;
17pub mod iso8601;
18pub mod rfc1123;
19
20pub fn parse_rfc3339(s: &str) -> crate::Result<OffsetDateTime> {
28 OffsetDateTime::parse(s, &Rfc3339).with_context(ErrorKind::DataConversion, || {
29 format!("unable to parse rfc3339 date '{s}")
30 })
31}
32
33pub fn to_rfc3339(date: &OffsetDateTime) -> String {
41 date.format(&Rfc3339).unwrap()
43}
44
45pub fn parse_rfc1123(s: &str) -> crate::Result<OffsetDateTime> {
59 Ok(PrimitiveDateTime::parse(s, RFC1123_FORMAT)
60 .with_context(ErrorKind::DataConversion, || {
61 format!("unable to parse rfc1123 date '{s}")
62 })?
63 .assume_utc())
64}
65
66const RFC1123_FORMAT: &[FormatItem] = format_description!(
67 "[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT"
68);
69
70pub fn to_rfc1123(date: &OffsetDateTime) -> String {
84 date.to_offset(UtcOffset::UTC);
85 date.format(&RFC1123_FORMAT).unwrap()
87}
88
89pub fn parse_last_state_change(s: &str) -> crate::Result<OffsetDateTime> {
95 Ok(PrimitiveDateTime::parse(s, LAST_STATE_CHANGE_FORMAT)
96 .with_context(ErrorKind::DataConversion, || {
97 format!("unable to parse last state change date '{s}")
98 })?
99 .assume_utc())
100}
101
102const LAST_STATE_CHANGE_FORMAT: &[FormatItem] = format_description!(
103 "[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second].[subsecond digits:3] GMT"
104);
105
106pub fn to_last_state_change(date: &OffsetDateTime) -> String {
112 date.to_offset(UtcOffset::UTC);
113 date.format(LAST_STATE_CHANGE_FORMAT).unwrap()
115}
116
117pub fn duration_from_minutes(minutes: u64) -> Duration {
119 Duration::from_secs(minutes * 60)
120}
121
122pub fn duration_from_hours(hours: u64) -> Duration {
124 Duration::from_secs(hours * 3_600)
125}
126
127pub fn duration_from_days(days: u64) -> Duration {
129 Duration::from_secs(days * 86_400)
130}
131
132pub fn diff(first: OffsetDateTime, second: OffsetDateTime) -> Duration {
134 (first - second).unsigned_abs()
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::from_json;
141 use serde::{Deserialize, Serialize};
142 use time::macros::datetime;
143
144 #[derive(Serialize, Deserialize)]
145 struct ExampleState {
146 #[serde(with = "crate::date::rfc3339")]
147 created_time: time::OffsetDateTime,
148
149 #[serde(default, with = "crate::date::rfc3339::option")]
151 deleted_time: Option<time::OffsetDateTime>,
152 }
153
154 #[test]
155 fn test_roundtrip_rfc3339() -> crate::Result<()> {
156 let s = "2019-10-12T07:20:50.52Z";
157 let dt = parse_rfc3339(s)?;
158 assert_eq!(s, to_rfc3339(&dt));
159 Ok(())
160 }
161
162 #[test]
163 fn test_device_update_dates() -> crate::Result<()> {
164 let created = parse_rfc3339("1999-09-10T21:59:22Z")?;
165 let last_action = parse_rfc3339("1999-09-10T03:05:07.3845533+01:00")?;
166 assert_eq!(created, datetime!(1999-09-10 21:59:22 UTC));
167 assert_eq!(last_action, datetime!(1999-09-10 03:05:07.3845533 +01));
168 Ok(())
169 }
170
171 #[test]
172 fn test_to_rfc1123() -> crate::Result<()> {
173 let dt = datetime!(1994-11-06 08:49:37 UTC);
174 assert_eq!("Sun, 06 Nov 1994 08:49:37 GMT", to_rfc1123(&dt));
175 Ok(())
176 }
177
178 #[test]
179 fn test_parse_rfc1123() -> crate::Result<()> {
180 let dt = datetime!(1994-11-06 08:49:37 UTC);
181 assert_eq!(parse_rfc1123("Sun, 06 Nov 1994 08:49:37 GMT")?, dt);
182 Ok(())
183 }
184
185 #[test]
186 fn test_parse_last_state_change() -> crate::Result<()> {
187 assert_eq!(
188 datetime!(2020-01-15 23:39:44.369 UTC),
189 parse_last_state_change("Wed, 15 Jan 2020 23:39:44.369 GMT")?
190 );
191 Ok(())
192 }
193
194 #[test]
195 fn test_list_blob_creation_time() -> crate::Result<()> {
196 let creation_time = "Thu, 01 Jul 2021 10:45:02 GMT";
197 assert_eq!(
198 datetime!(2021-07-01 10:45:02 UTC),
199 parse_rfc1123(creation_time)?
200 );
201 Ok(())
202 }
203
204 #[test]
205 fn test_serde_rfc3339_none_optional() -> crate::Result<()> {
206 let json_state = r#"{
207 "created_time": "2021-07-01T10:45:02Z"
208 }"#;
209
210 let state: ExampleState = from_json(json_state)?;
211
212 assert_eq!(parse_rfc3339("2021-07-01T10:45:02Z")?, state.created_time);
213 assert_eq!(state.deleted_time, None);
214
215 Ok(())
216 }
217
218 #[test]
219 fn test_serde_rfc3339_some_optional() -> crate::Result<()> {
220 let json_state = r#"{
221 "created_time": "2021-07-01T10:45:02Z",
222 "deleted_time": "2022-03-28T11:05:31Z"
223 }"#;
224
225 let state: ExampleState = from_json(json_state)?;
226
227 assert_eq!(parse_rfc3339("2021-07-01T10:45:02Z")?, state.created_time);
228 assert_eq!(
229 state.deleted_time,
230 Some(parse_rfc3339("2022-03-28T11:05:31Z")?)
231 );
232
233 Ok(())
234 }
235}