1 版本说明
本文定义紧凑时长 1格式(Compact Duration Format)的 2.0 版。1.0 定义的表示在 2.0 中仍然有效,数值含义不变。
与 1.0 相比,2.0 明确以下内容:
- 完整的词法与语法;
- 合法形式与规范形式;
- 单位进位与数值范围;
- 非负约束;
- 展示形式的选择原则;
- 统一的失败情形。
3w2d1h20m33s 等 1.0 写法在 2.0 中仍然合法,数值含义不变。
2 规范用语
本文中的「必须」「不得」「应」「不应」「可以」按 RFC 2119 解释:
| 用语 | 含义 |
|---|---|
| 必须 | 绝对要求 |
| 不得 | 绝对禁止 |
| 应 | 推荐;有充分理由时可以偏离,但应理解其后果 |
| 不应 | 不推荐 |
| 可以 | 可选 |
3 设计目标
工程配置里常见的 timeout: 3600 需要翻文档确认单位;自由文本 2小时30分 人类易读但机器难以统一解析;ISO 8601 的 P3W2DT1H20M33S 足够严谨,但在配置、日志和状态描述中读写成本偏高。
紧凑时长格式面向项目内部的高频读写场景,目标如下:
- 人工可以直接读出时长;
- 机器可以无歧义地解析为精确数值;
- 任意两个表示可以按数值比较;
- 展示可以优先人类阅读;
- 规范只约束语法和数值语义,不约束展示形式的选择。
本格式是项目级规范,不追求覆盖 ISO 8601 的全部日历语义,也不宣称在语法上与其兼容。
4 语法
4.1 词法
Duration = UnitPart+ ;
UnitPart = Number Unit ;
Number = Digit+ ;
Digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
Unit = "w" | "d" | "h" | "m" | "s" | "ms" | "us" | "ns" ;
- 字符串必须只包含 ASCII 字符。
- 单位必须为小写;大写不属于合法形式。
- 各时间单元之间不得包含空格、制表符或其他分隔符。
- 单位必须按最长匹配识别:在数字之后依次尝试
ns、us、ms、w、d、h、m、s。因此500ms必须解释为 500 毫秒,不得解释为 500 分钟加一个孤立的s。 - 本格式不包含符号位;负值不属于本格式。
4.2 单位
核心单位必须支持:
| 单位 | 含义 | 等价关系 |
|---|---|---|
w |
周 | 7d |
d |
天 | 24h |
h |
小时 | 60m |
m |
分钟 | 60s |
s |
秒 | 基础单位 |
扩展单位可以支持:
| 单位 | 含义 | 等价关系 |
|---|---|---|
ms |
毫秒 | 1/1000 s |
us |
微秒 | 1/1000 ms |
ns |
纳秒 | 1/1000 us |
- 实现必须支持全部核心单位。
- 实现可以支持扩展单位;支持的扩展单位集合由实现确定。
- 使用方不得假定扩展单位一定被支持。
- 对于不支持的扩展单位,解析必须失败,不得静默舍入或截断。
4.3 保留单位
y(年)、mo(月)、a(年)为保留单位,不属于本格式,必须拒绝。
月份长度为 28 至 31 天,年份长度为 365 或 366 天,都无法无歧义地换算为固定秒数。需要日历周期时,应使用独立的格式,不得混入本格式。
4.4 顺序
多个单位同时出现时,必须按时间尺度由大到小排列:
w → d → h → m → s → ms → us → ns
单位必须严格降序,且不得重复。顺序固定之后,格式才不需要任何分隔符。
4.5 非负约束
本格式只表示非负时长。负值表示方向,不属于时长本身;需要在格式之外表达。
5 合法形式与规范形式
本规范定义两种表示:合法形式和规范形式。
- 合法形式是语法上可以解析的表示。
- 规范形式是一种确定性的默认表示,便于需要固定字符串的场合。
规范保证的唯一性是数值唯一:任何合法形式都必须解析为同一个精确数值,而不是要求所有实现输出同一个字符串。
5.1 合法形式
满足以下条件的字符串是合法形式:
- 符合词法定义;
- 至少包含一个时间单元;
- 单位严格降序,且不重复;
- 只使用核心单位或实现支持的扩展单位;
- 数值为非负十进制整数,可以包含前导零;
- 总时长不超过本规范规定的最大值。
合法形式不是唯一表示。例如 90s 与 1m30s 都是合法形式,且表示同一时长。
5.2 规范形式
规范形式是确定性的默认表示,必须同时满足:
- 数字不含前导零;
- 除整体的
0s外,不得包含值为0的时间单元; - 必须按进位关系完成全部可进位;
- 单位严格降序,且不重复;
- 零时长必须表示为
0s; - 只使用核心单位或实现支持的扩展单位。
规范形式是推荐的固定字符串表示。它不是唯一的合法表示,展示可以使用其他合法形式。
6 进位
规范形式中的进位关系如下:
| 低位表示 | 等价高位表示 |
|---|---|
1000ns |
1us |
1000us |
1ms |
1000ms |
1s |
60s |
1m |
60m |
1h |
24h |
1d |
7d |
1w |
在规范形式中,必须按此表完成全部可进位。展示形式不受此限制。
以下示例假定扩展单位已支持:
| 输入 | 规范形式 |
|---|---|
60s |
1m |
90m |
1h30m |
24h |
1d |
7d |
1w |
30d |
4w2d |
2h0m30s |
2h30s |
1h60m |
2h |
1000ms |
1s |
1s1000ms |
2s |
1w7d |
2w |
01s |
1s |
0m |
0s |
7 数值范围
本规范表示的最大时长为 2^63−1 纳秒,约为 292 年。
- 实现必须支持
0到最大值的完整范围。 - 总时长超过最大值的表示不是合法形式,解析必须失败。
- 不得回绕、截断或饱和。
8 解析与校验
- 解析合法形式必须得到精确的总时长。
- 需要确定字符串表示时,应生成规范形式。
- 比较必须按总时长进行,不得按字符串进行。
- 实现可以提供严格校验;严格校验只接受规范形式,其他输入必须失败。
- 大小写混写、空格分隔、
µs、中文长写等不属于合法形式。
9 失败情形
以下情形用于区分解析失败的原因:
| 情形 | 触发条件 | 示例 |
|---|---|---|
E_EMPTY |
空字符串 | 空串 |
E_LEX |
含空白、小数点、负号、全角字符或其他非法字符 | 2h 30m、1.5h、-1h |
E_UNIT |
未知单位、保留单位或大小写不符 | 1y、1mo、1H |
E_FORMAT |
数字与单位配对错误 | 0、h、1h30 |
E_ORDER |
单位不是严格降序 | 30m2h |
E_DUP |
同一单位出现多次 | 1h2h |
E_PRECISION |
使用了实现不支持的扩展单位 | 不支持 ms 时的 500ms |
E_OVERFLOW |
超出本规范的最大时长 | 999999999999999999999w |
E_NONCANONICAL |
严格校验下输入不是规范形式 | 严格校验下的 60s |
10 展示
规范保证解析结果数值唯一,展示可以优先人类阅读。
- 实现可以自行选择合适的单位展示。例如,在习惯以天读数的场景中,
30d比4w2d更易读;在习惯以秒读数的场景中,90s比1m30s更易读。 - 本规范不规定展示形式的选择规则,也不要求展示形式与规范形式一致。
- 展示形式必须是合法形式。
- 同一时长的不同展示形式必须解析为同一数值。
- 展示形式不改变语法或数值语义。
11 与其他格式的关系
本节为定位说明,不构成规范要求。
| 特性 | 紧凑时长 2.0 | ISO 8601 Duration | Go time.Duration |
|---|---|---|---|
| 基本写法 | 3w2d1h20m33s |
P3W2DT1H20M33S |
74h20m33s |
| 日历单位 | 不支持 | 支持年和月 | 不支持 |
| 固定单位 | w d h m s |
W D H M S |
h m s ms us ns |
| 小数 | 不支持 | 支持 | 支持 |
| 负号 | 不支持 | 视具体表示法而定 | 支持 |
| 分隔符 | 无 | P、T |
无 |
| 大小写 | 只接受小写 | 大写 | 小写 |
- 需要与外部系统交换标准时长数据时,应使用 ISO 8601。
- 本格式坚持整数,以保证精确;需要更细粒度时,使用扩展单位。
- 本格式只表示非负时长;负值表达方向,不属于时长本身。
- 不支持小数,是因为有限小数不一定能在有限精度内精确表示,会引入舍入和数值歧义。
12 持续时间而非时间点
紧凑时长格式表示持续时间,而不是时间点。3d12h 表示一个持续 3 天 12 小时的长度,不表示 2026-11-08 12:00 这样的时刻。时间点应使用独立的 Date-Time 或 Timestamp 格式。
把一个持续时长加到某个时间点上属于日历运算,涉及时区、夏令时和月份边界等规则,应另行定义。本格式只定义固定长度时长本身。
13 一致性测试向量
下表可用于验证解析和规范化的行为:
- 第 1 至 9 行、第 13 至 14 行:核心单位,所有实现必须通过;
- 第 10 至 12 行:扩展单位,仅支持对应扩展单位的实现需要通过;
- 第 15 至 26 行:失败情形与严格校验,提供严格校验的实现需要通过。
| 序号 | 输入 | 行为 | 期望结果 |
|---|---|---|---|
| 1 | 0s |
规范化解析 | 0s |
| 2 | 30s |
规范化解析 | 30s |
| 3 | 60s |
规范化解析 | 1m |
| 4 | 90m |
规范化解析 | 1h30m |
| 5 | 24h |
规范化解析 | 1d |
| 6 | 7d |
规范化解析 | 1w |
| 7 | 30d |
规范化解析 | 4w2d |
| 8 | 2h0m30s |
规范化解析 | 2h30s |
| 9 | 1h60m |
规范化解析 | 2h |
| 10 | 1s1000ms |
规范化解析 | 2s |
| 11 | 1000ms |
规范化解析 | 1s |
| 12 | 500ms |
规范化解析 | 500ms |
| 13 | 01s |
规范化解析 | 1s |
| 14 | 1w7d |
规范化解析 | 2w |
| 15 | 1h2h |
严格校验 | E_DUP |
| 16 | 30m2h |
严格校验 | E_ORDER |
| 17 | 2h 30m |
严格校验 | E_LEX |
| 18 | 1.5h |
严格校验 | E_LEX |
| 19 | -1h |
严格校验 | E_LEX |
| 20 | 1y |
严格校验 | E_UNIT |
| 21 | 1H |
严格校验 | E_UNIT |
| 22 | 0 |
严格校验 | E_FORMAT |
| 23 | 空字符串 | 严格校验 | E_EMPTY |
| 24 | 60s |
严格校验 | E_NONCANONICAL |
| 25 | 500ms |
严格校验,实现不支持 ms |
E_PRECISION |
| 26 | 999999999999999999999w |
严格校验 | E_OVERFLOW |
14 从 1.0 到 2.0 的变更
14.1 兼容性
- 五个核心单位的顺序和无分隔符写法不变。
- 1.0 的进位和去零规则在 2.0 中继续作为规范形式的要求。
- 1.0 的合法写法在 2.0 中仍然合法,数值含义不变。
14.2 新增与明确
| 项目 | 1.0 | 2.0 |
|---|---|---|
| 合法与规范 | 只提出应规范化 | 明确两种形式及其关系 |
| 数值唯一性 | 未明确 | 明确为解析结果的数值唯一 |
| 展示形式 | 未涉及 | 明确可以选择更易读的合法形式 |
| 进位 | 原则性描述 | 完整进位关系 |
| 范围 | 未定义 | 0 到 2^63−1 纳秒 |
| 扩展单位 | 可选 | 可选;不支持时必须失败 |
| 负时长 | 未定义 | 明确不支持 |
| 失败情形 | 未定义 | 统一分类 |
| 保留字 | 未定义 | y、mo、a 必须拒绝 |
15 参考引用
- RFC 2119:https://www.rfc-editor.org/rfc/rfc2119(规范性用语定义)
- ISO 8601:https://en.wikipedia.org/wiki/ISO_8601(日期与时间表示的国际标准)
- Go time.ParseDuration:https://pkg.go.dev/time#ParseDuration(Go 标准库的时长解析)
- 紧凑时长格式 1.0:https://srs.pub/thinking/compact-duration.html(上一版规范)