diff --git a/src/report.rs b/src/report.rs index 09357e8..db4da69 100644 --- a/src/report.rs +++ b/src/report.rs @@ -51,24 +51,44 @@ const MIN_BAR_WIDTH: usize = 8; /// Format a duration in seconds into a human-readable string. /// +/// Once the duration reaches a full day it is reported in days and hours +/// (minutes are dropped, with the leftover hour rounded to the nearest hour). +/// /// Examples: -/// - 45 seconds → "45s" -/// - 120 seconds → "2m" +/// - 45 seconds → "45s" +/// - 120 seconds → "2m" /// - 3660 seconds → "1h 01m" -/// - 0 seconds → "0s" +/// - 0 seconds → "0s" +/// - 90000 secs → "1d 1h" +/// - 86400 secs → "1d" pub fn format_duration(secs: i64) -> String { + const HOUR: i64 = 3600; + const DAY: i64 = 86400; if secs < 60 { format!("{}s", secs) - } else if secs < 3600 { + } else if secs < HOUR { format!("{}m", secs / 60) - } else { - let hours = secs / 3600; - let mins = (secs % 3600) / 60; + } else if secs < DAY { + let hours = secs / HOUR; + let mins = (secs % HOUR) / 60; if mins == 0 { format!("{}h", hours) } else { format!("{}h {:02}m", hours, mins) } + } else { + let mut days = secs / DAY; + // Round the leftover hours to the nearest hour, carrying into days. + let mut hours = (secs % DAY + HOUR / 2) / HOUR; + if hours == 24 { + days += 1; + hours = 0; + } + if hours == 0 { + format!("{}d", days) + } else { + format!("{}d {}h", days, hours) + } } } @@ -1333,8 +1353,9 @@ tr:last-child td { border-bottom: none; } color: #a99984; background: linear-gradient(135deg, #17130d, #2c2116); font-size: 12px; } .pin-dot { position: absolute; top: 5px; right: 5px; width: 22px; height: 22px; - border-radius: 50%; background: rgba(0,0,0,0.45); border: none; - cursor: pointer; font-size: 12px; line-height: 22px; text-align: center; + border-radius: 50%; background: rgba(0,0,0,0.45); border: none; padding: 0; + cursor: pointer; font-size: 12px; line-height: 1; + display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.15s; z-index: 1; } .album:hover .pin-dot { opacity: 1; } .pin-dot:hover { background: rgba(0,0,0,0.75); } @@ -1752,6 +1773,16 @@ mod tests { assert_eq!(format_duration(0), "0s"); } + #[test] + fn test_format_duration_days() { + assert_eq!(format_duration(86400), "1d"); + assert_eq!(format_duration(90000), "1d 1h"); + // 1d 5h 40m rounds up to 1d 6h. + assert_eq!(format_duration(106800), "1d 6h"); + // Leftover hours rounding up to 24 carries into the next day. + assert_eq!(format_duration(172799), "2d"); + } + #[test] fn test_format_play_count() { assert_eq!(format_play_count(0), "0 plays");