diff options
| author | Jonas Maier <> | 2026-03-07 20:49:52 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-07 20:49:52 +0100 |
| commit | df5eec13a031d41232e7407794e2f5b9a0a2d608 (patch) | |
| tree | a76fba2ed68928d82d9b8352bfd0afc33d118fb0 /src/date.rs | |
| parent | 86cdb8c21dec737a3f0a40311782de851c1203d1 (diff) | |
| download | pish-df5eec13a031d41232e7407794e2f5b9a0a2d608.tar.gz | |
history with relative time
Diffstat (limited to 'src/date.rs')
| -rw-r--r-- | src/date.rs | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/src/date.rs b/src/date.rs new file mode 100644 index 0000000..149dc79 --- /dev/null +++ b/src/date.rs @@ -0,0 +1,113 @@ +use core::fmt; +use std::{ + process::Command, + time::{Duration, SystemTime}, +}; + +use crate::BString; + +#[derive(Clone)] +pub struct DateTime { + sys: SystemTime, +} + +impl DateTime { + pub fn from_unix(unix: u64) -> Self { + Self { + sys: SystemTime::UNIX_EPOCH + Duration::from_secs(unix), + } + } + pub fn now() -> Self { + Self { + sys: SystemTime::now(), + } + } + fn format(&self) -> std::io::Result<BString> { + let mut out = Command::new("date") + .arg("-d") + .arg(format!( + "@{}", + self.sys + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() + )) + .output()? + .stdout; + while let Some(x) = out.last() + && x.is_ascii_whitespace() + { + out.pop(); + } + Ok(out) + } + + fn unix(&self) -> u64 { + self.sys + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap() + .as_secs() + } + + pub fn relative_to(&self, other: &Self) -> String { + let a = self.unix(); + let b = other.unix(); + + let (pre, post, mut diff) = if a < b { + ("in ", "", b - a) + } else { + ("", " ago", a - b) + }; + + let unit = if diff < 60 { + "s" + } else if { + diff /= 60; + diff < 60 + } { + "m" + } else if { + diff /= 60; + diff < 24 + } { + "h" + } else if { + diff /= 24; + diff < 365 + } { + "d" + } else { + diff /= 365; + "y" + }; + + format!("{pre}{diff}{unit}{post}") + } + + pub const fn longest_reasonable_delta() -> usize { + 7 + } +} + +#[test] +fn long_delta() { + assert_eq!( + DateTime::now() + .relative_to(&DateTime { + // 30 years ago + sys: SystemTime::now() - Duration::from_secs(60 * 60 * 24 * 365 * 30) + }) + .len(), + DateTime::longest_reasonable_delta() + ); +} + +impl fmt::Display for DateTime { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + String::from_utf8_lossy(&self.format().unwrap_or_else(|_| Vec::new())) + ) + } +} |
