subtile/time/
time_point.rs

1use core::fmt;
2use std::ops::Neg;
3
4/// Define a time in milliseconds
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct TimePoint(i64);
7
8impl TimePoint {
9    /// Create a `TimePoint` from milliseconds
10    #[must_use]
11    pub const fn from_msecs(time: i64) -> Self {
12        Self(time)
13    }
14
15    /// Create a `TimePoint` from seconds
16    ///
17    /// # Panics
18    ///
19    /// Will panics if the `seconds` value fill as parameter is to big to be store as
20    /// millisecond in a [`i64`].
21    #[must_use]
22    pub fn from_secs(seconds: f64) -> Self {
23        let msecs = cast::i64(seconds * 1000.0).unwrap();
24        Self(msecs)
25    }
26
27    /// Convert to seconds
28    #[must_use]
29    pub fn to_secs(self) -> f64 {
30        self.0 as f64 / 1000.
31    }
32
33    /// Get milliseconds corresponding to `TimePoint`.
34    #[must_use]
35    pub const fn msecs(self) -> i64 {
36        self.0
37    }
38
39    const fn secs(self) -> i64 {
40        self.0 / 1000
41    }
42
43    const fn mins(self) -> i64 {
44        self.0 / (60 * 1000)
45    }
46
47    const fn hours(self) -> i64 {
48        self.0 / (60 * 60 * 1000)
49    }
50    const fn mins_comp(self) -> i64 {
51        self.mins() % 60
52    }
53
54    const fn secs_comp(self) -> i64 {
55        self.secs() % 60
56    }
57
58    const fn msecs_comp(self) -> i64 {
59        self.msecs() % 1000
60    }
61}
62
63impl Neg for TimePoint {
64    type Output = Self;
65    fn neg(self) -> Self {
66        Self(-self.0)
67    }
68}
69
70impl TimePoint {
71    ///TODO
72    /// # Errors
73    ///
74    /// Will return error of writing if happen.
75    pub fn fmt_separator(&self, f: &mut fmt::Formatter<'_>, separator: char) -> fmt::Result {
76        let t = if self.0 < 0 { -*self } else { *self };
77        write!(
78            f,
79            "{}{:02}:{:02}:{:02}{separator}{:03}",
80            if self.0 < 0 { "-" } else { "" },
81            t.hours(),
82            t.mins_comp(),
83            t.secs_comp(),
84            t.msecs_comp()
85        )
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn time_point_creation() {
95        assert_eq!(TimePoint::from_msecs(6751), TimePoint(6751));
96        assert_eq!(TimePoint::from_msecs(142), TimePoint::from_secs(0.142));
97    }
98
99    #[test]
100    fn time_point_creation_with_too_much_decimals() {
101        assert_eq!(TimePoint::from_msecs(265), TimePoint::from_secs(0.265_579));
102        assert_eq!(TimePoint(142), TimePoint::from_secs(0.142_75));
103    }
104
105    #[test]
106    fn time_point_msecs() {
107        const TIME: i64 = 62487;
108        assert_eq!(TimePoint::from_msecs(TIME).msecs(), TIME);
109    }
110
111    #[test]
112    fn time_point_secs() {
113        const TIME: f64 = 624.87;
114        assert_eq!(TimePoint::from_secs(TIME).secs(), 624);
115    }
116
117    #[test]
118    fn to_big_seconds() {
119        const TIME: f64 = 9_223_372_036_854_776.; // i64::MAX + 1 as f64 / 1000 + round
120        let result = std::panic::catch_unwind(|| TimePoint::from_secs(TIME));
121        assert!(result.is_err());
122    }
123}