|
|
@@ -1,8 +1,10 @@
|
|
|
//! Timestamp formatting.
|
|
|
|
|
|
-use std::time::{SystemTime, UNIX_EPOCH};
|
|
|
+use std::convert::TryInto;
|
|
|
+use std::cmp::max;
|
|
|
+use std::time::{SystemTime, UNIX_EPOCH, Duration};
|
|
|
|
|
|
-use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
|
|
|
+use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Instant};
|
|
|
use datetime::fmt::DateFormat;
|
|
|
|
|
|
use lazy_static::lazy_static;
|
|
|
@@ -46,6 +48,9 @@ pub enum TimeFormat {
|
|
|
/// millisecond and includes its offset down to the minute. This too uses
|
|
|
/// only numbers so doesn’t require any special consideration.
|
|
|
FullISO,
|
|
|
+
|
|
|
+ /// Use a relative but fixed width representation.
|
|
|
+ Relative,
|
|
|
}
|
|
|
|
|
|
// There are two different formatting functions because local and zoned
|
|
|
@@ -58,6 +63,7 @@ impl TimeFormat {
|
|
|
Self::ISOFormat => iso_local(time),
|
|
|
Self::LongISO => long_local(time),
|
|
|
Self::FullISO => full_local(time),
|
|
|
+ Self::Relative => relative(time),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -67,6 +73,7 @@ impl TimeFormat {
|
|
|
Self::ISOFormat => iso_zoned(time, zone),
|
|
|
Self::LongISO => long_zoned(time, zone),
|
|
|
Self::FullISO => full_zoned(time, zone),
|
|
|
+ Self::Relative => relative(time),
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -113,6 +120,21 @@ fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
|
|
|
date.hour(), date.minute())
|
|
|
}
|
|
|
|
|
|
+#[allow(trivial_numeric_casts)]
|
|
|
+fn relative(time: SystemTime) -> String {
|
|
|
+ format!(
|
|
|
+ "{:>13}",
|
|
|
+ timeago::Formatter::new().convert(
|
|
|
+ Duration::from_secs(
|
|
|
+ max(0, Instant::now().seconds() - systemtime_epoch(time))
|
|
|
+ // this .unwrap is safe since the call above can never result in a
|
|
|
+ // value < 0
|
|
|
+ .try_into().unwrap()
|
|
|
+ )
|
|
|
+ )
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
#[allow(trivial_numeric_casts)]
|
|
|
fn full_local(time: SystemTime) -> String {
|
|
|
let date = LocalDateTime::at(systemtime_epoch(time));
|