contained_core/
epoch.rs

1/*
2    Appellation: epoch <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4    Description: ... Summary ...
5*/
6use decanter::prelude::Hashable;
7use serde::{Deserialize, Serialize};
8use std::time::Duration;
9
10pub enum EpochPerspective {
11    Before,
12    During,
13    After,
14}
15
16/// An [Epoch] consists of a start time and optionally, a duration (seconds). If None, the system assumes an infinite duration
17#[derive(
18    Clone, Copy, Debug, Deserialize, Eq, Hash, Hashable, Ord, PartialEq, PartialOrd, Serialize,
19)]
20pub struct Epoch {
21    pub duration: Duration,
22    pub start: i64,
23}
24
25impl Epoch {
26    pub fn new(duration: Option<Duration>, start: impl Into<i64>) -> Self {
27        Self {
28            duration: duration.unwrap_or_else(|| Duration::from_secs(1)),
29            start: start.into(),
30        }
31    }
32    pub fn duration(&self) -> Duration {
33        self.duration
34    }
35    /// Returns the [Duration] of time since the [Epoch] was created
36    pub fn elapsed(&self) -> Duration {
37        let now: i64 = chrono::Utc::now().timestamp();
38        Duration::from_secs((now - self.start) as u64)
39    }
40    /// Returns the end time of the [Epoch]
41    pub fn end(&self) -> i64 {
42        self.start + self.duration.as_secs() as i64
43    }
44    /// Returns true if the epoch has expired
45    pub fn is_expired(&self) -> bool {
46        self.elapsed() > self.duration
47    }
48    /// Returns the start time of the [Epoch]
49    pub fn start(&self) -> i64 {
50        self.start
51    }
52    pub fn tstep(&self, n: usize) -> Vec<i64> {
53        let step_size = self.duration.div_f64(n as f64).as_secs() as i64;
54        (0..n)
55            .map(|i| self.start + (i as i64 * step_size))
56            .collect()
57    }
58}
59
60impl Default for Epoch {
61    fn default() -> Self {
62        Self::new(Some(Duration::new(1, 0)), chrono::Utc::now().timestamp())
63    }
64}
65
66impl std::fmt::Display for Epoch {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        write!(f, "{}", serde_json::to_string(&self).unwrap())
69    }
70}
71
72impl From<Duration> for Epoch {
73    fn from(duration: Duration) -> Self {
74        Self::new(Some(duration), chrono::Utc::now().timestamp())
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_epoch() {
84        let epoch = Epoch::from(Duration::new(2, 0));
85        assert_eq!(epoch.duration(), Duration::new(2, 0));
86        assert_eq!(
87            epoch.end(),
88            epoch.start() + epoch.duration().as_secs() as i64
89        );
90        assert_eq!(epoch.is_expired(), false);
91        assert_eq!(epoch.tstep(1), vec![epoch.start()]);
92        assert_eq!(
93            epoch.tstep(2),
94            vec![
95                epoch.start(),
96                epoch.start() + epoch.duration().div_f64(2.0).as_secs() as i64
97            ]
98        );
99    }
100}