OXYGENHUB
◆ v0.4.1 oxygenhub / crates / hub / src / render / time.rs
2.0 KiB · Rust · last changed Milestone 0.1: browse 1 month ago source blame history raw
1
//! Times as people read them: relative ("3 hours ago") with the absolute
2
//! form for a tooltip.
3
4
use time::format_description::well_known::Rfc3339;
5
use time::OffsetDateTime;
6
7
/// `just now`, `5 minutes ago`, `3 days ago`, `2 years ago`.
8
pub fn ago(when_ms: u64, now_ms: u64) -> String {
9
    if when_ms == 0 {
10
        return "unknown".into();
11
    }
12
    if when_ms > now_ms {
13
        return "in the future".into();
14
    }
15
    let s = (now_ms - when_ms) / 1000;
16
    let (n, unit) = if s < 45 {
17
        return "just now".into();
18
    } else if s < 90 {
19
        (1, "minute")
20
    } else if s < 3600 {
21
        (s / 60, "minute")
22
    } else if s < 86_400 {
23
        (s / 3600, "hour")
24
    } else if s < 86_400 * 30 {
25
        (s / 86_400, "day")
26
    } else if s < 86_400 * 365 {
27
        (s / (86_400 * 30), "month")
28
    } else {
29
        (s / (86_400 * 365), "year")
30
    };
31
    format!("{n} {unit}{} ago", if n == 1 { "" } else { "s" })
32
}
33
34
/// `2026-09-27 17:02 UTC`.
35
pub fn absolute(when_ms: u64) -> String {
36
    match OffsetDateTime::from_unix_timestamp((when_ms / 1000) as i64) {
37
        Ok(t) => {
38
            let f = time::macros::format_description!("[year]-[month]-[day] [hour]:[minute] UTC");
39
            t.format(&f).unwrap_or_default()
40
        }
41
        Err(_) => String::new(),
42
    }
43
}
44
45
pub fn rfc3339(when_ms: u64) -> String {
46
    OffsetDateTime::from_unix_timestamp((when_ms / 1000) as i64).ok().and_then(|t| t.format(&Rfc3339).ok()).unwrap_or_default()
47
}
48
49
#[cfg(test)]
50
mod tests {
51
    use super::*;
52
53
    #[test]
54
    fn relative() {
55
        let now = 1_800_000_000_000;
56
        assert_eq!(ago(now - 10_000, now), "just now");
57
        assert_eq!(ago(now - 60_000, now), "1 minute ago");
58
        assert_eq!(ago(now - 5 * 60_000, now), "5 minutes ago");
59
        assert_eq!(ago(now - 3 * 3_600_000, now), "3 hours ago");
60
        assert_eq!(ago(now - 2 * 86_400_000, now), "2 days ago");
61
        assert_eq!(ago(now - 400 * 86_400_000, now), "1 year ago");
62
        assert_eq!(ago(0, now), "unknown");
63
        assert_eq!(absolute(1_758_990_120_000), "2025-09-27 16:22 UTC");
64
    }
65
}