Skip to content

Commit 40b2497

Browse files
committed
Allow HumanDuration to be more precise for sub-second durations
1 parent 48de84b commit 40b2497

2 files changed

Lines changed: 32 additions & 8 deletions

File tree

src/format.rs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,37 @@ pub struct HumanDuration(pub Duration);
2424

2525
impl fmt::Display for HumanDuration {
2626
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
27+
if self.0 == Duration::ZERO {
28+
return write!(f, "0 seconds");
29+
}
30+
2731
let mut idx = 0;
2832
for (i, &(cur, _, _)) in UNITS.iter().enumerate() {
2933
idx = i;
3034
match UNITS.get(i + 1) {
35+
// Stop if value minus half of the next smaller unit is above 1.5x current unit
3136
Some(&next) if self.0.saturating_add(next.0 / 2) >= cur + cur / 2 => break,
3237
_ => continue,
3338
}
3439
}
3540

3641
let (unit, name, alt) = UNITS[idx];
42+
if self.0 < Duration::new(1, 900_000_000) {
43+
let precision = if self.0 > Duration::from_millis(150) {
44+
1
45+
} else if self.0 > Duration::from_millis(15) {
46+
2
47+
} else {
48+
3
49+
};
50+
51+
let s = self.0.as_secs_f64();
52+
return match f.alternate() {
53+
true => write!(f, "{s:.*}s", precision),
54+
false => write!(f, "{s:.*} seconds", precision),
55+
};
56+
}
57+
3758
// FIXME when `div_duration_f64` is stable
3859
let mut t = (self.0.as_secs_f64() / unit.as_secs_f64()).round() as usize;
3960
if idx < UNITS.len() - 1 {
@@ -231,22 +252,25 @@ mod tests {
231252
"0 seconds",
232253
format!("{}", HumanDuration(Duration::from_secs(0)))
233254
);
234-
assert_eq!("0 seconds", format!("{}", HumanDuration(MILLI)));
235-
assert_eq!("0 seconds", format!("{}", HumanDuration(499 * MILLI)));
236-
assert_eq!("1 second", format!("{}", HumanDuration(500 * MILLI)));
237-
assert_eq!("1 second", format!("{}", HumanDuration(999 * MILLI)));
255+
assert_eq!("0.001 seconds", format!("{}", HumanDuration(MILLI)));
256+
assert_eq!("0.008 seconds", format!("{}", HumanDuration(8 * MILLI)));
257+
assert_eq!("0.011 seconds", format!("{}", HumanDuration(11 * MILLI)));
258+
assert_eq!("0.02 seconds", format!("{}", HumanDuration(17 * MILLI)));
259+
assert_eq!("0.5 seconds", format!("{}", HumanDuration(499 * MILLI)));
260+
assert_eq!("0.5 seconds", format!("{}", HumanDuration(500 * MILLI)));
261+
assert_eq!("1.0 seconds", format!("{}", HumanDuration(999 * MILLI)));
238262
}
239263

240264
#[test]
241265
fn human_duration_less_than_two_seconds() {
242-
assert_eq!("1 second", format!("{}", HumanDuration(1499 * MILLI)));
243-
assert_eq!("2 seconds", format!("{}", HumanDuration(1500 * MILLI)));
266+
assert_eq!("1.5 seconds", format!("{}", HumanDuration(1499 * MILLI)));
267+
assert_eq!("1.5 seconds", format!("{}", HumanDuration(1500 * MILLI)));
244268
assert_eq!("2 seconds", format!("{}", HumanDuration(1999 * MILLI)));
245269
}
246270

247271
#[test]
248272
fn human_duration_one_unit() {
249-
assert_eq!("1 second", format!("{}", HumanDuration(SECOND)));
273+
assert_eq!("1.0 seconds", format!("{}", HumanDuration(SECOND)));
250274
assert_eq!("60 seconds", format!("{}", HumanDuration(MINUTE)));
251275
assert_eq!("60 minutes", format!("{}", HumanDuration(HOUR)));
252276
assert_eq!("24 hours", format!("{}", HumanDuration(DAY)));

tests/render.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ fn progress_bar_terminal_wrap() {
10821082
in_mem.contents(),
10831083
r#" Finished downloa
10841084
ding 435.96 KiB in 0
1085-
s"#
1085+
.000s"#
10861086
);
10871087

10881088
println!("{:?}", in_mem.contents())

0 commit comments

Comments
 (0)