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
use chrono::{DateTime, Duration, Utc};

pub trait DurationExtension {
    fn weeks(self) -> Duration;
    fn days(self) -> Duration;
    fn hours(self) -> Duration;
    fn minutes(self) -> Duration;
    fn seconds(self) -> Duration;
    fn milliseconds(self) -> Duration;
    fn microseconds(self) -> Duration;
    fn nanoseconds(self) -> Duration;
}

pub trait DateTimeExtension {
    fn before(self, other: DateTime<Utc>) -> DateTime<Utc>;
    fn after(self, other: DateTime<Utc>) -> DateTime<Utc>;

    fn ago(self) -> DateTime<Utc>
    where
        Self: DateTimeExtension + Sized,
    {
        self.before(Utc::now())
    }

    fn from_now(self) -> DateTime<Utc>
    where
        Self: DateTimeExtension + Sized,
    {
        self.after(Utc::now())
    }
}

macro_rules! duration_extension {
    ($($type:ident), +) => {
        impl DurationExtension for i64 {
            $(
                fn $type(self) -> Duration {
                    Duration::$type(self)
                }
            )*
        }
    };
}
duration_extension!(
    weeks,
    days,
    hours,
    minutes,
    seconds,
    milliseconds,
    microseconds,
    nanoseconds
);

impl DateTimeExtension for Duration {
    fn before(self, other: DateTime<Utc>) -> DateTime<Utc> {
        other - self
    }

    fn after(self, other: DateTime<Utc>) -> DateTime<Utc> {
        other + self
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use chrono::{Duration, Utc};

    #[test]
    fn duration() {
        assert_eq!(2.weeks(), Duration::weeks(2));
        assert_eq!(2.days(), Duration::days(2));
        assert_eq!(2.hours(), Duration::hours(2));
        assert_eq!(2.minutes(), Duration::minutes(2));
        assert_eq!(2.seconds(), Duration::seconds(2));
        assert_eq!(2.milliseconds(), Duration::milliseconds(2));
        assert_eq!(2.microseconds(), Duration::microseconds(2));
        assert_eq!(2.nanoseconds(), Duration::nanoseconds(2));
    }

    #[test]
    fn days_before() {
        let now = Utc::now();
        assert_eq!(2.days().before(now), now - Duration::days(2));
    }

    #[test]
    fn days_after() {
        let now = Utc::now();
        assert_eq!(2.days().after(now), now + Duration::days(2));
    }
}