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
pub trait Hhmmss {
    fn sms(&self) -> (i64, i64);
    /// Pretty-prints a chrono::Duration in the form `HH:MM:SS.xxx`
    fn hhmmss(&self) -> String {
        let (s, ms) = self.sms();
        s2hhmmss(s)
    }
    /// Pretty-prints a chrono::Duration in the form `HH:MM:SS.xxx`
    fn hhmmssxxx(&self) -> String {
        let (s, ms) = self.sms();
        sms2hhmmsxxx(s, ms)
    }
}

impl Hhmmss for chrono::Duration {
    fn sms(&self) -> (i64, i64) {
        let s = self.num_seconds();
        let ms = self.num_milliseconds() - 1000 * s;
        (s, ms)
    }
}

impl Hhmmss for std::time::Duration {
    fn sms(&self) -> (i64, i64) {
        let s = self.as_secs();
        let ms = self.subsec_millis();
        (s as i64, ms as i64)
    }
}

impl Hhmmss for time::Duration {
    fn sms(&self) -> (i64, i64) {
        let s = self.whole_seconds();
        let ms = self.whole_milliseconds() as i64 - 1000 * s;
        (s, ms)
    }
}

fn s2hhmmss(s: i64) -> String {
    let mut neg = false;
    let mut s = s;
    if s < 0 {
        neg = true;
        s = -s;
    }
    let (h, s) = (s / 3600, s % 3600);
    let (m, s) = (s / 60, s % 60);
    format!("{}{:02}:{:02}:{:02}", if neg { "-" } else { "" }, h, m, s)
}

fn sms2hhmmsxxx(s: i64, ms: i64) -> String {
    let mut neg = false;
    let (mut s, mut ms) = (s, ms);
    if s < 0 {
        neg = true;
        s = -s;
        ms = -ms;
    }
    let (h, s) = (s / 3600, s % 3600);
    let (m, s) = (s / 60, s % 60);
    format!(
        "{}{:02}:{:02}:{:02}.{:03}",
        if neg { "-" } else { "" },
        h,
        m,
        s,
        ms
    )
}

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

    #[test]
    fn test_all() {
        let std_duration = std::time::Duration::new(3661, 534_000_000);
        assert_eq!(&std_duration.hhmmss(), "01:01:01");
        assert_eq!(&std_duration.hhmmssxxx(), "01:01:01.534");
        let chrono_duration = chrono::Duration::from_std(std_duration).unwrap();
        assert_eq!(&chrono_duration.hhmmss(), "01:01:01");
        assert_eq!(&chrono_duration.hhmmssxxx(), "01:01:01.534");
        let time_duration = time::Duration::from_std(std_duration).unwrap();
        assert_eq!(&time_duration.hhmmss(), "01:01:01");
        assert_eq!(&time_duration.hhmmssxxx(), "01:01:01.534");
    }
}