humantime_fmt/lib.rs
1//! # humantime_fmt
2//!
3//! A lightweight Rust crate to convert `SystemTime` values into
4//! human-friendly relative time strings like "just now", "yesterday", or "in 3 days".
5//!
6//! ## Features
7//! - Works with past and future times relative to now
8//! - Granular output: seconds, minutes, hours, yesterday, days, last week, weeks
9//!
10//! ## Example
11//!
12//! ```rust
13//! use humantime_fmt::format_relative;
14//! use std::time::{SystemTime, Duration};
15//!
16//! let now = SystemTime::now();
17//! let past = now - Duration::from_secs(90);
18//! let future = now + Duration::from_secs(3600);
19//!
20//! assert_eq!(format_relative(past), "1 minute ago");
21//! assert_eq!(format_relative(future), "in 1 hour");
22//! ```
23
24use std::time::SystemTime;
25
26/// Formats a [`SystemTime`] into a human-readable relative time string.
27///
28/// The output is relative to the current system time (`SystemTime::now()`),
29/// producing strings such as:
30/// - `"just now"`
31/// - `"5 minutes ago"`
32/// - `"2 hours ago"`
33/// - `"yesterday"`
34/// - `"last week"`
35/// - `"in 3 days"`
36/// - `"next week"`
37///
38/// # Arguments
39///
40/// * `time` - The `SystemTime` value to format relative to now.
41///
42/// # Returns
43///
44/// A `String` describing the relative time.
45///
46/// # Examples
47///
48/// ```rust
49/// use humantime_fmt::format_relative;
50/// use std::time::{SystemTime, Duration};
51///
52/// let now = SystemTime::now();
53/// let past = now - Duration::from_secs(90);
54/// let future = now + Duration::from_secs(3600);
55///
56/// assert_eq!(format_relative(past), "1 minute ago");
57/// assert_eq!(format_relative(future), "in 1 hour");
58/// ```
59pub fn format_relative(time: SystemTime) -> String {
60 let now = SystemTime::now();
61 let diff = match time.duration_since(now) {
62 Ok(dur) => dur,
63 Err(e) => e.duration(),
64 };
65
66 let is_future = time > now;
67 let seconds = diff.as_secs();
68
69 let (prefix, suffix) = if is_future {
70 ("in ", "")
71 } else {
72 ("", " ago")
73 };
74
75 let output = if seconds < 60 {
76 "just now".to_string()
77 } else if seconds < 3600 {
78 let minutes = seconds / 60;
79 format!("{}{minutes} minute{}{}", prefix, if minutes != 1 { "s" } else { "" }, suffix)
80 } else if seconds < 86400 {
81 let hours = seconds / 3600;
82 format!("{}{hours} hour{}{}", prefix, if hours != 1 { "s" } else { "" }, suffix)
83 } else if seconds < 172800 {
84 if is_future {
85 "tomorrow".to_string()
86 } else {
87 "yesterday".to_string()
88 }
89 } else if seconds < 604800 {
90 let days = seconds / 86400;
91 format!("{}{days} day{}{}", prefix, if days != 1 { "s" } else { "" }, suffix)
92 } else if seconds < 1209600 {
93 if is_future {
94 "next week".to_string()
95 } else {
96 "last week".to_string()
97 }
98 } else {
99 let weeks = seconds / 604800;
100 format!("{}{weeks} week{}{}", prefix, if weeks != 1 { "s" } else { "" }, suffix)
101 };
102
103 output
104}