chrono_human_duration/
lib.rs1use 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}