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
134
135
136
//! milli_time_mod

use chrono::Timelike;
use std::fmt;

/// milli_time format is fixed and global: from `000md` to `999md`, always 3 digits, no space, suffix `md`
pub struct MilliTime {
    milliday: u32,
}

impl MilliTime {
    /// constructor from hour, minute, second, rounded to 1md
    /// returns None on error
    /// # Example
    /// ```
    /// let millis = veeks_millis::MilliTime::from_hms(13,53,58).unwrap();
    /// assert_eq!(millis.to_string(),"579md");
    /// ```
    pub fn from_hms(hour: u32, minute: u32, second: u32) -> Option<Self> {
        if hour >= 24 || minute >= 60 || second >= 60 {
            return None;
        }
        //return
        Some(MilliTime {
            milliday: ((hour * 3600 + minute * 60 + second) as f64 / 86.4).round() as u32,
        })
    }

    /// constructor from chrono NaiveTime, rounded to 1md
    /// # Example
    ///
    /// ```
    /// let nt = chrono::NaiveTime::from_hms(13,30,00);
    /// let millis = veeks_millis::MilliTime::from_naive_time(nt);
    /// assert_eq!(millis.milliday(),563);
    /// ```
    pub fn from_naive_time(nt: chrono::NaiveTime) -> Self {
        // return
        MilliTime {
            milliday: (nt.num_seconds_from_midnight() as f64 / 86.4).round() as u32,
        }
    }
    /// constructor from string millis `000md` to `999md`
    /// returns None if unrecognized format
    /// # Example
    ///
    /// ```
    /// let millis = veeks_millis::MilliTime::from_str("560md").unwrap();
    /// assert_eq!(millis.milliday(),560);
    /// ```
    pub fn from_str(s: &str) -> Option<Self> {
        // ok() Converts from Result<T, E> to Option<T>.
        if s.len() != 5 {
            return None;
        };
        let milliday = s.get(0..3)?.parse::<u32>().ok()?;
        let millis_unit = s.get(3..5)?;
        if millis_unit != "md" {
            return None;
        };
        // return
        Some(MilliTime { milliday })
    }
    /// getter milliday f64
    /// # Example
    /// ```
    /// let veeks = veeks_millis::MilliTime::from_hms(13,53,58).unwrap();
    /// assert_eq!(veeks.milliday(),579);
    /// ```
    pub fn milliday(&self) -> u32 {
        // return
        self.milliday
    }

    /// convert millis to chrono NaiveTime rounded to 1 second
    /// returns None if error
    /// # Example
    ///
    /// ```
    /// let millis = veeks_millis::MilliTime::from_str("560md").unwrap();
    /// let nt = millis.to_naive_time().unwrap();
    /// assert_eq!(nt,chrono::NaiveTime::from_hms(13,26,24));
    /// ```
    pub fn to_naive_time(&self) -> Option<chrono::NaiveTime> {
        chrono::NaiveTime::from_num_seconds_from_midnight_opt(
            (self.milliday as f64 * 86.4).round() as u32,
            0,
        )
    }
}

/// the Trait Display implements fn to_string() implicitly
impl fmt::Display for MilliTime {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // return
        write!(f, r#"{:03}md"#, self.milliday)
    }
}

#[cfg(test)]
mod test {
    // use unwrap::unwrap;

    #[test]
    pub fn t07_naive_time_to_millis() {
        let nt = chrono::NaiveTime::from_hms(13, 30, 00);
        let millis = super::MilliTime::from_naive_time(nt);
        assert_eq!(millis.milliday, 563);
    }

    #[test]
    pub fn t08_naive_time_to_millis_str() {
        let nt = chrono::NaiveTime::from_hms(13, 30, 00);
        let millis = super::MilliTime::from_naive_time(nt);
        assert_eq!(millis.to_string(), "563md");
    }

    #[test]
    pub fn t09_millis_from_str_opt() {
        let millis = super::MilliTime::from_str("560md").unwrap();
        assert_eq!(millis.milliday(), 560);
    }

    #[test]
    #[should_panic]
    pub fn t10_millis_from_str_opt_should_panic() {
        let _millis = super::MilliTime::from_str("560 md").unwrap();
    }

    #[test]
    pub fn t11_millis_to_naive_time_opt() {
        let millis = super::MilliTime::from_str("560md").unwrap();
        let nt = millis.to_naive_time().unwrap();
        assert_eq!(nt, chrono::NaiveTime::from_hms(13, 26, 24));
    }
}