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
use derive_more::{AsMut, AsRef, Deref, Display, From, Into};
use serde::{Deserialize, Serialize};
#[cfg(feature = "speedy")]
use speedy::{Readable, Writable};
use std::ops::{Add, Sub};
use std::time::Duration;

/// An integer count of the number of seconds from 1st January 1970.
/// This does not count any of the leap seconds that have occurred, it
/// simply presumes UTC never had leap seconds; yet it is well known
/// and well understood.
#[derive(
    AsMut,
    AsRef,
    Clone,
    Copy,
    Debug,
    Deref,
    Deserialize,
    Display,
    Eq,
    From,
    Into,
    Ord,
    PartialEq,
    PartialOrd,
    Serialize,
)]
#[cfg_attr(feature = "speedy", derive(Readable, Writable))]
pub struct Unixtime(pub i64);

impl Unixtime {
    /// Get the current unixtime (depends on the system clock being accurate)
    pub fn now() -> Unixtime {
        Unixtime(std::time::UNIX_EPOCH.elapsed().unwrap().as_secs() as i64)
    }

    // Mock data for testing
    #[allow(dead_code)]
    pub(crate) fn mock() -> Unixtime {
        Unixtime(1668572286)
    }
}

impl Add<Duration> for Unixtime {
    type Output = Self;

    fn add(self, rhs: Duration) -> Self::Output {
        Unixtime(self.0 + rhs.as_secs() as i64)
    }
}

impl Sub<Duration> for Unixtime {
    type Output = Self;

    fn sub(self, rhs: Duration) -> Self::Output {
        Unixtime(self.0 - rhs.as_secs() as i64)
    }
}

impl Sub<Unixtime> for Unixtime {
    type Output = Duration;

    fn sub(self, rhs: Unixtime) -> Self::Output {
        Duration::from_secs((self.0 - rhs.0).unsigned_abs())
    }
}

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

    test_serde! {Unixtime, test_unixtime_serde}

    #[test]
    fn test_print_now() {
        println!("NOW: {}", Unixtime::now());
    }

    #[test]
    fn test_unixtime_math() {
        let now = Unixtime::now();
        let fut = now + Duration::from_secs(70);
        assert!(fut > now);
        assert_eq!(fut.0 - now.0, 70);
        let back = fut - Duration::from_secs(70);
        assert_eq!(now, back);
        assert_eq!(now - back, Duration::ZERO);
    }
}