Skip to main content

mps/elements/
log_elem.rs

1use super::split_args;
2
3#[derive(Debug, Clone)]
4pub struct LogData {
5    pub tags: Vec<String>,
6    pub start: Option<String>, // "HH:MM"
7    pub end: Option<String>,   // "HH:MM"
8}
9
10impl LogData {
11    pub fn parse_args(raw: &str) -> Self {
12        let p = split_args(raw);
13        LogData {
14            tags: p.tags,
15            start: p.attrs.get("start").cloned(),
16            end: p.attrs.get("end").cloned(),
17        }
18    }
19
20    /// Duration in minutes, or None if start/end are not both present.
21    pub fn duration_minutes(&self) -> Option<i64> {
22        let s = self.start.as_deref()?;
23        let e = self.end.as_deref()?;
24        let (sh, sm) = parse_hhmm(s)?;
25        let (eh, em) = parse_hhmm(e)?;
26        Some((eh * 60 + em) - (sh * 60 + sm))
27    }
28
29    /// "3h30m" or "3h" or None.
30    pub fn duration_str(&self) -> Option<String> {
31        let mins = self.duration_minutes()?;
32        if mins <= 0 {
33            return None;
34        }
35        let h = mins / 60;
36        let m = mins % 60;
37        if m > 0 {
38            Some(format!("{}h{}m", h, m))
39        } else {
40            Some(format!("{}h", h))
41        }
42    }
43}
44
45fn parse_hhmm(s: &str) -> Option<(i64, i64)> {
46    let mut parts = s.splitn(2, ':');
47    let h: i64 = parts.next()?.trim().parse().ok()?;
48    let m: i64 = parts.next()?.trim().parse().ok()?;
49    Some((h, m))
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_duration_str() {
58        let d = LogData::parse_args("work, start: 09:00, end: 12:30");
59        assert_eq!(d.duration_str(), Some("3h30m".into()));
60    }
61
62    #[test]
63    fn test_exact_hours() {
64        let d = LogData::parse_args("start: 09:00, end: 12:00");
65        assert_eq!(d.duration_str(), Some("3h".into()));
66    }
67
68    #[test]
69    fn test_no_times() {
70        let d = LogData::parse_args("work");
71        assert_eq!(d.duration_str(), None);
72    }
73
74    #[test]
75    fn test_duration_minutes() {
76        let d = LogData::parse_args("start: 09:00, end: 12:30");
77        assert_eq!(d.duration_minutes(), Some(210));
78    }
79}