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
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
use chrono::{DateTime, NaiveDateTime, Utc};
use std::fmt;

pub trait InnerTimestampConverter: Clone + Copy + PartialEq + Eq + PartialOrd + Ord {
    type Inner: Clone + Copy + PartialEq + Eq + PartialOrd + Ord;

    fn into_inner(ts: NaiveDateTime) -> Self::Inner;

    fn from_inner(ts: Self::Inner) -> NaiveDateTime;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SecondsTimestampConverter;

impl InnerTimestampConverter for SecondsTimestampConverter {
    type Inner = i64;

    fn into_inner(ts: NaiveDateTime) -> Self::Inner {
        ts.timestamp()
    }

    fn from_inner(ts: Self::Inner) -> NaiveDateTime {
        NaiveDateTime::from_timestamp(ts, 0)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MillisecondsTimestampConverter;

impl InnerTimestampConverter for MillisecondsTimestampConverter {
    type Inner = i64;

    fn into_inner(ts: NaiveDateTime) -> Self::Inner {
        ts.timestamp_millis()
    }

    fn from_inner(ts: Self::Inner) -> NaiveDateTime {
        NaiveDateTime::from_timestamp(ts / 1000i64, (ts % 1000i64) as u32 * 1_000_000u32)
    }
}

// A generic timestamp
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct GenericTimestamp<C: InnerTimestampConverter>(C::Inner);

impl<C: InnerTimestampConverter> GenericTimestamp<C> {
    pub fn now() -> Self {
        Utc::now().into()
    }

    pub fn from_inner(from: C::Inner) -> Self {
        Self(from)
    }

    pub fn into_inner(self) -> C::Inner {
        self.0
    }

    pub fn from_seconds(seconds: i64) -> Self {
        Self(C::into_inner(SecondsTimestampConverter::from_inner(
            seconds,
        )))
    }

    pub fn from_milliseconds(milliseconds: i64) -> Self {
        Self(C::into_inner(MillisecondsTimestampConverter::from_inner(
            milliseconds,
        )))
    }

    pub fn into_seconds(self) -> i64 {
        C::from_inner(self.0).timestamp()
    }

    pub fn into_milliseconds(self) -> i64 {
        C::from_inner(self.0).timestamp_millis()
    }
}

impl<C: InnerTimestampConverter> From<NaiveDateTime> for GenericTimestamp<C> {
    fn from(from: NaiveDateTime) -> Self {
        Self(C::into_inner(from))
    }
}

impl<C: InnerTimestampConverter> From<GenericTimestamp<C>> for NaiveDateTime {
    fn from(from: GenericTimestamp<C>) -> Self {
        C::from_inner(from.0)
    }
}

impl<C: InnerTimestampConverter> From<DateTime<Utc>> for GenericTimestamp<C> {
    fn from(from: DateTime<Utc>) -> Self {
        Self(C::into_inner(from.naive_utc()))
    }
}

impl<C: InnerTimestampConverter> From<GenericTimestamp<C>> for DateTime<Utc> {
    fn from(from: GenericTimestamp<C>) -> Self {
        Self::from_utc(NaiveDateTime::from(from), Utc)
    }
}

impl<C: InnerTimestampConverter> fmt::Display for GenericTimestamp<C> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), std::fmt::Error> {
        write!(f, "{}", DateTime::<Utc>::from(self.to_owned()))
    }
}

pub type Timestamp = GenericTimestamp<SecondsTimestampConverter>;

pub type TimestampMs = GenericTimestamp<MillisecondsTimestampConverter>;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn convert_from_into_inner() {
        let t1 = Timestamp::now();
        let i1 = t1.into_inner();
        let t2 = Timestamp::from_inner(i1);
        assert_eq!(t1, t2);
    }

    #[test]
    fn convert_from_into_inner_ms() {
        let t1 = TimestampMs::now();
        let i1 = t1.into_inner();
        let t2 = TimestampMs::from_inner(i1);
        assert_eq!(t1, t2);
    }
}