功能说明
format_duration 把秒数格式化为 1d 2h 3m 4s 这样的可读文本,parse_duration 执行反向解析,把 1d 2h 30m 或 1h30m 转回秒数。两者适合命令行工具的输出、配置文件中的超时时间、任务耗时展示以及用户输入的时间跨度。max_units 控制最多显示几个单位,compact 控制是否省略空格。
格式化先对秒数四舍五入,再依次用天、小时、分钟、秒做整除和取余。解析使用正则逐个匹配数值和单位,允许单位之间没有空格、大小写混用和小数,但要求整个字符串都被消费,遇到 1h 30 这类缺少单位的尾部会抛错。
关键代码
解析循环从当前位置继续匹配,匹配失败立即报告剩余文本:
while position < len(value):
match = _TOKEN.match(value, position)
if match is None:
raise ValueError(
f"invalid duration at position {position}: "
f"{value[position:]!r}"
)
amount = float(match.group(1))
unit = match.group(2).lower()
total += amount * _UNIT_SECONDS[unit]
position = match.end()
format_duration 用 divmod 同时得到当前单位的值和余数,避免重复计算。
使用注意
格式化默认只保留两个最高单位,例如 3661 秒输出 1h 1m,秒数被截断;需要完整精度时把 max_units 设为 4。四舍五入使用 Python 的银行家舍入,正好处于 .5 的秒数可能向偶数方向取整,若业务要求始终向上应自行调整。负数、NaN 和无穷大会被拒绝。
解析允许小数和重复单位,例如 1h 30m 10m 会把两个分钟相加;单位顺序也不受限制。它不支持 1 hour、1h30 或负数。空字符串和只有空白的字符串会报错。返回值是浮点秒数,可能包含浮点误差;需要整数时可在调用方取整。格式化与解析不保证完全互逆,因为格式化受 max_units 和舍入影响。
验证方式
示例输出 0、45、3661、90061、172800 秒的可读形式,分别为 0s、45s、1h 1m、1d 1h、2d,紧凑模式 1h1m。解析 1d 2h 30m 应得到 95400 秒,1h30m 得到 5400 秒。解析 1h 30 应输出带位置的错误,格式化 -1 应输出非负有限数错误。