1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
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()))
)
}
}
|