Skip to main content

chrono_human_duration/
lib.rs

1use chrono::Duration;
2use std::fmt;
3
4pub trait ChronoHumanDuration {
5    type Displayer: fmt::Display;
6    fn format_human(&self) -> Self::Displayer;
7}
8
9impl ChronoHumanDuration for Duration {
10    type Displayer = Displayer;
11    fn format_human(&self) -> Self::Displayer {
12        Displayer { d: *self }
13    }
14}
15
16pub struct Displayer {
17    d: Duration,
18}
19
20impl fmt::Display for Displayer {
21    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22        let mut wrote = false;
23        let d = self.d;
24
25        let weeks = d.num_weeks();
26        if weeks > 0 {
27            write!(f, "{} week{}", weeks, if weeks == 1 { "s" } else { "" })?;
28            wrote = true;
29        } else {
30            let days = d.num_days();
31            if days > 0 {
32                write!(
33                    f,
34                    "{}{} day{}",
35                    if wrote { ", " } else { "" },
36                    days,
37                    if days == 1 { "s" } else { "" }
38                )?;
39                wrote = true;
40            } else {
41                let hours = d.num_hours();
42                if hours > 0 {
43                    write!(
44                        f,
45                        "{}{} hour{}",
46                        if wrote { ", " } else { "" },
47                        hours,
48                        if days == 1 { "s" } else { "" }
49                    )?;
50                    wrote = true;
51                }
52            }
53        }
54
55        if wrote {
56            write!(f, " ago")
57        } else {
58            write!(f, "just now")
59        }
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::ChronoHumanDuration;
66    use chrono::Duration;
67
68    #[test]
69    fn it_works() {
70        let d = Duration::weeks(2) + Duration::days(3) + Duration::hours(2) + Duration::minutes(20);
71        assert_eq!(d.format_human().to_string(), "2 weeks ago");
72        let d = Duration::minutes(20);
73        assert_eq!(d.format_human().to_string(), "just now");
74    }
75}