xelf/
datetime.rs

1use ::chrono::prelude::*;
2
3#[cfg(feature = "sea-orm")]
4pub use ::sea_orm::prelude::DateTimeUtc;
5#[cfg(not(feature = "sea-orm"))]
6pub type DateTimeUtc = DateTime<Utc>;
7
8/// Unix timestamp in microseconds
9pub type UnixTimeMicros = i64;
10
11/// Duration in microseconds
12pub type DurationMicros = i64;
13
14pub trait UnixTimestampXlf: Sized {
15    /// Convert days into microseconds.
16    fn micros_from_days(&self) -> Self;
17
18    /// Convert hours into microseconds.
19    fn micros_from_hours(&self) -> Self;
20
21    /// Convert minutes into microseconds.
22    fn micros_from_mins(&self) -> Self;
23
24    /// Convert seconds into microseconds.
25    fn micros_from_secs(&self) -> Self;
26
27    /// Convert seconds into microseconds.
28    fn micros_from_secs_f64(secs: f64) -> Self;
29
30    /// Convert milliseconds into microseconds.
31    fn micros_from_millis(&self) -> Self;
32
33    /// Convert the UNIX timestamp in milliseconds into `DateTimeUtc`.
34    fn micros_as_unix_timestamp(&self) -> DateTimeUtc;
35
36    /// Convert the UNIX timestamp in milliseconds into `DateTimeUtc` with error.
37    fn micros_as_unix_timestamp_opt(&self) -> chrono::LocalResult<DateTimeUtc>;
38
39    /// Get the current UNIX timestamp in microseconds.
40    fn micros_now() -> Self;
41
42    /// Get the UNIX timestamp from a UTC string or a timestamp in microseconds.
43    fn micros_from_utc_str(s: impl AsRef<str>) -> Option<Self>;
44
45    /// Convert into a UTC string.
46    fn micros_into_utc_str(&self) -> String;
47}
48
49/// Get the default value for `DateTime<Utc>`, the Unix Epoch at 1970-01-01T00:00:00Z.
50#[inline]
51pub fn utc_default() -> DateTimeUtc {
52    Utc.timestamp_opt(0, 0).unwrap()
53}
54
55/// Parses an RFC 3339 date-and-time string into a `DateTimeUtc` value.
56pub fn utc_from_str(s: &str) -> chrono::ParseResult<DateTimeUtc> {
57    DateTime::parse_from_rfc3339(s).map(DateTime::<Utc>::from)
58}
59
60/// Convert a `DateTimeUtc` value into an RFC 3339 date-and-time string
61/// with the format `YYYY-MM-DDTHH:MM:SS.SSSSSSZ`.
62pub fn utc_into_str(utc: DateTimeUtc) -> String {
63    let n = utc.naive_local();
64    format!(
65        "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:06}Z",
66        n.year(),
67        n.month(),
68        n.day(),
69        n.hour(),
70        n.minute(),
71        n.second(),
72        n.nanosecond() / 1000
73    )
74}
75
76impl UnixTimestampXlf for UnixTimeMicros {
77    #[inline]
78    fn micros_from_days(&self) -> Self {
79        self * (24 * 60 * 60 * 1_000_000)
80    }
81
82    #[inline]
83    fn micros_from_hours(&self) -> Self {
84        self * (60 * 60 * 1_000_000)
85    }
86
87    #[inline]
88    fn micros_from_mins(&self) -> Self {
89        self * (60 * 1_000_000)
90    }
91
92    #[inline]
93    fn micros_from_secs(&self) -> Self {
94        self * 1_000_000
95    }
96
97    #[inline]
98    fn micros_from_secs_f64(secs: f64) -> Self {
99        (secs * 1_000_000.0) as Self
100    }
101
102    fn micros_from_millis(&self) -> Self {
103        self * 1_000
104    }
105
106    fn micros_as_unix_timestamp(&self) -> DateTimeUtc {
107        self.micros_as_unix_timestamp_opt()
108            .single()
109            .unwrap_or_else(utc_default)
110    }
111
112    fn micros_as_unix_timestamp_opt(&self) -> chrono::LocalResult<DateTimeUtc> {
113        let (mut secs, mut micros) = (self / 1_000_000, self % 1_000_000);
114        if micros < 0 {
115            secs -= 1;
116            micros += 1_000_000;
117        }
118        Utc.timestamp_opt(secs, micros as u32 * 1_000)
119    }
120
121    fn micros_now() -> Self {
122        Utc::now().timestamp_micros()
123    }
124
125    fn micros_from_utc_str(s: impl AsRef<str>) -> Option<Self> {
126        let s = s.as_ref();
127        s.parse::<UnixTimeMicros>().ok().or_else(|| {
128            DateTime::parse_from_rfc3339(s)
129                .ok()
130                .map(|x| DateTime::<Utc>::from(x).timestamp_micros())
131        })
132    }
133
134    fn micros_into_utc_str(&self) -> String {
135        utc_into_str(self.micros_as_unix_timestamp())
136    }
137}
138
139////////////////////////////////////////////////////////////////////////////////
140
141/// Module to serialize and deserialize a **`DateTimeUtc`**
142#[cfg(feature = "serde")]
143pub mod serde_x_utc {
144    use super::*;
145    use ::serde::{
146        de::{self, Unexpected},
147        ser::Serializer,
148    };
149    use ::std::fmt;
150
151    struct DeUtcVisitor;
152
153    impl<'de> de::Visitor<'de> for DeUtcVisitor {
154        type Value = DateTime<Utc>;
155
156        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
157            write!(formatter, "a formatted date and time string")
158        }
159
160        // from seconds
161        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
162        where
163            E: de::Error,
164        {
165            match Utc.timestamp_millis_opt(value as i64).single() {
166                Some(v) => Ok(v),
167                _ => Err(de::Error::invalid_type(Unexpected::Unsigned(value), &self)),
168            }
169        }
170
171        // from seconds
172        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
173        where
174            E: de::Error,
175        {
176            match Utc.timestamp_millis_opt(value).single() {
177                Some(v) => Ok(v),
178                _ => Err(de::Error::invalid_type(Unexpected::Signed(value), &self)),
179            }
180        }
181
182        // from seconds as float
183        fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
184        where
185            E: de::Error,
186        {
187            let secs = value.floor();
188            match Utc
189                .timestamp_opt(secs as i64, ((value - secs) * 1000000000.) as u32)
190                .single()
191            {
192                Some(v) => Ok(v),
193                _ => Err(de::Error::invalid_type(Unexpected::Float(value), &self)),
194            }
195        }
196
197        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
198        where
199            E: de::Error,
200        {
201            match DateTime::parse_from_rfc3339(value) {
202                Ok(v) => Ok(DateTime::<Utc>::from(v)),
203                _ => Err(de::Error::invalid_type(Unexpected::Str(value), &self)),
204            }
205        }
206    }
207
208    struct DeUtcMicrosVisitor;
209
210    impl<'de> de::Visitor<'de> for DeUtcMicrosVisitor {
211        type Value = UnixTimeMicros;
212
213        fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
214            write!(formatter, "a formatted date and time string")
215        }
216
217        // from microseconds
218        fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
219        where
220            E: de::Error,
221        {
222            UnixTimeMicros::try_from(value)
223                .map_err(|_| de::Error::invalid_type(Unexpected::Unsigned(value), &self))
224        }
225
226        // from microseconds
227        fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
228        where
229            E: de::Error,
230        {
231            Ok(value)
232        }
233
234        // from microseconds as float
235        fn visit_f64<E>(self, value: f64) -> Result<Self::Value, E>
236        where
237            E: de::Error,
238        {
239            Ok(value as i64)
240        }
241
242        fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
243        where
244            E: de::Error,
245        {
246            match DateTime::parse_from_rfc3339(value) {
247                Ok(v) => Ok(DateTime::<Utc>::from(v).timestamp_micros()),
248                _ => Err(de::Error::invalid_type(Unexpected::Str(value), &self)),
249            }
250        }
251    }
252
253    /// Function to serializing a **`DateTimeUtc`**
254    pub fn serialize<S>(utc: &DateTimeUtc, serializer: S) -> Result<S::Ok, S::Error>
255    where
256        S: Serializer,
257    {
258        serializer.serialize_str(&utc_into_str(*utc))
259    }
260
261    /// Function to deserializing a **`DateTimeUtc`**
262    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTimeUtc, D::Error>
263    where
264        D: de::Deserializer<'de>,
265    {
266        deserializer.deserialize_any(DeUtcVisitor)
267    }
268
269    pub mod f64 {
270        use super::*;
271
272        /// Function to serializing a **`DateTimeUtc`**
273        pub fn serialize<S>(utc: &DateTimeUtc, serializer: S) -> Result<S::Ok, S::Error>
274        where
275            S: Serializer,
276        {
277            serializer.serialize_f64(utc.timestamp_micros() as f64 / 1000000.)
278        }
279
280        /// Function to deserializing a **`DateTimeUtc`**
281        pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTimeUtc, D::Error>
282        where
283            D: de::Deserializer<'de>,
284        {
285            deserializer.deserialize_f64(DeUtcVisitor)
286        }
287    }
288
289    pub mod micros {
290        use super::*;
291
292        /// Function to serializing a **`DateTimeUtc`**
293        pub fn serialize<S>(micros: UnixTimeMicros, serializer: S) -> Result<S::Ok, S::Error>
294        where
295            S: Serializer,
296        {
297            serializer.serialize_i64(micros)
298        }
299
300        /// Function to deserializing a **`DateTimeUtc`**
301        pub fn deserialize<'de, D>(deserializer: D) -> Result<UnixTimeMicros, D::Error>
302        where
303            D: de::Deserializer<'de>,
304        {
305            deserializer.deserialize_i64(DeUtcMicrosVisitor)
306        }
307    }
308}
309
310#[cfg(feature = "serde")]
311pub use serde_x_utc::{deserialize as de_x_utc, serialize as ser_x_utc};
312#[cfg(feature = "serde")]
313pub use serde_x_utc::{f64::deserialize as de_x_utc_f64, f64::serialize as ser_x_utc_f64};
314#[cfg(feature = "serde")]
315pub use serde_x_utc::{
316    micros::deserialize as de_x_utc_micros, micros::serialize as ser_x_utc_micros,
317};
318
319////////////////////////////////////////////////////////////////////////////////
320
321#[cfg(test)]
322mod tests {
323    #[cfg(feature = "serde")]
324    #[test]
325    fn test_utc_default() {
326        use super::*;
327        use crate::prelude::*;
328
329        #[derive(Clone, Debug, SmartDefault, Serialize, Deserialize)]
330        struct Person {
331            #[serde(default)]
332            name: String,
333            year: i32,
334            optional: Option<i32>,
335            //#[serde(with = "serde_x_utc", default = "utc_default")]
336            #[serde(default = "utc_default")]
337            #[default(utc_default())]
338            birth_on: DateTime<Utc>,
339        }
340
341        let jsn = json!({
342            "year": 32,
343            "birth_on": utc_into_str(Utc::now()),
344        });
345        let a: Person = serde_json::from_value(jsn).unwrap();
346        println!("{:?}", &a);
347
348        let s = serde_json::to_string(&a).unwrap();
349        println!("{}", &s);
350
351        let utc = utc_from_str("2022-01-01T00:00:01.345677Z").unwrap();
352        assert_eq!(
353            UnixTimeMicros::micros_from_utc_str("2022-01-01T00:00:01.345677Z"),
354            Some(utc.timestamp_micros())
355        );
356        assert_eq!(
357            UnixTimeMicros::micros_from_utc_str(utc.timestamp_micros().to_string()),
358            Some(utc.timestamp_micros())
359        );
360    }
361}