from typing import List _UNITS = (("d", 86400), ("h", 3600), ("m", 60), ("s", 1)) def format_duration(seconds: int, max_units: int) -> str: """Seconds as "3h 12m". Starts at the largest non-zero unit and looks at max_units consecutive units from there, leaving out the zero ones, so 3605 s with two units is "1h", not "1h 0m" and not "1h 5s": the seconds are beyond the precision asked for. Truncates, never rounds up, so a duration is never shown longer than it was (86399 s is "23h", not "1d").""" if not isinstance(seconds, int) or isinstance(seconds, bool): raise ValueError("seconds must be a whole number, received %r" % (seconds,)) if seconds < 0: raise ValueError("seconds must not be negative, received %d" % seconds) if not isinstance(max_units, int) or isinstance(max_units, bool) or max_units < 1 or max_units > 4: raise ValueError("maxUnits must be 1 to 4, received %r" % (max_units,)) if seconds == 0: return "0s" first = 0 while seconds // _UNITS[first][1] == 0: first += 1 parts: List[str] = [] rest = seconds for i, (label, size) in enumerate(_UNITS): n = rest // size rest -= n * size if first <= i < first + max_units and n > 0: parts.append("%d%s" % (n, label)) return " ".join(parts)