1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
use std::ops::Deref;

use chrono::{DateTime, NaiveDateTime, Utc, NaiveDate, NaiveTime};


/// this struct is practically a parser for
/// RFC3339-compliant strings and their abbreviated forms.
#[derive(Clone)]
pub struct Rfc3339Datetime {
    timestamp: DateTime<Utc>
}

impl From<&str> for Rfc3339Datetime {
    fn from(s: &str) -> Self {
        if let Ok(timestamp) = DateTime::parse_from_rfc3339(s) {
            return Self{timestamp: timestamp.with_timezone(&chrono::Utc)}
        }
        
        if let Ok(timestamp) = NaiveDateTime::parse_from_str(s, "%Y-%m-%dT%H:%M:%S") {
            return Self{timestamp: DateTime::<Utc>::from_naive_utc_and_offset(timestamp, Utc)}
        }

        if let Ok(timestamp) = NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S") {
            return Self{timestamp: DateTime::<Utc>::from_naive_utc_and_offset(timestamp, Utc)}
        }

        if let Ok(timestamp) = NaiveDate::parse_from_str(s, "%Y-%m-%d") {
            let time = NaiveTime::from_hms_opt(0, 0, 0).unwrap();
            let timestamp = NaiveDateTime::new(timestamp, time);
            return Self{timestamp: DateTime::<Utc>::from_naive_utc_and_offset(timestamp, Utc)}
        }

        panic!("invalid timestamp: '{s}'");
    }
}

impl Deref for Rfc3339Datetime {
    type Target = DateTime<Utc>;

    fn deref(&self) -> &Self::Target {
        &self.timestamp
    }
}