Intl.DurationFormat S4
中文标题:Intl.DurationFormat 提案
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2025
- 同步时间: 2026年8月26日
- English original · 官方仓库
该提案引入了 Intl.DurationFormat,这是一个新的 Intl API,用于对时间持续时间进行区域设置感知的格式化。它支持多个持续时间单位、格式化宽度(长、短、窄、数字)、按单位的样式/显示选项以及亚秒小数的显示。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
Intl.DurationFormat 提案
阶段: 4
提案负责人: Younies Mahmoud, Ujjwal Sharma
作者: Younies Mahmoud, Ujjwal Sharma
阶段 3 审阅者
- Michael Ficarra @michaelficarra
- Ron Buckton @rbuckton
- Ross Kirsling @rkirsling
资源
状态
- 该提案在 2020 年 2 月的 TC39 会议上达到阶段 1。
- 该提案在 2020 年 6 月的 TC39 会议上达到阶段 2。
- 该提案在 2021 年 10 月的 TC39 会议上达到阶段 3。
- 该提案在 2024 年 12 月的 TC39 会议上达到阶段 4。
概述
- 时间持续时间是指某事从开始到结束持续多长时间。它可以由单个时间单位或多个时间单位表示。
- 例如,
- 10000 秒
- 2 小时 46 分钟 40 秒
- 例如,
- 每个地区都有自己的持续时间格式化方式。
- 例如:
- en-US: 1 hour, 46 minutes and 40 seconds
- fr-FR: 1 heure, 46 minutes et 40 secondes
- 例如:
- 时间持续时间有多种宽度。
- 例如,宽和短
- 1 hour, 46 minutes and 40 seconds → 宽
- 1 hr, 46 min, 40 sec → 短
- 例如,宽和短
快速开始
动机
- 用户需要根据其应用程序的要求来进行各种类型的持续时间格式化。例如,要显示航班飞行时间,持续时间应为短格式或窄格式
- "1 hr 40 min 60 sec" → 短
- "1h 40m 60s" → 窄
需求与设计
在本节中,我们将说明每个用户需求以及每个需求的设计
支持的持续时间单位
- 用户需要以下字段支持
- 年
- 月
- 周
- 日
- 小时
- 分钟
- 秒
- 毫秒
- 微秒
- 纳秒
设计
- 持续时间对象支持与
Temporal.Duration相同的字段,其中包含:- years
- months
- weeks
- days
- hours
- minutes
- seconds
- milliseconds
- microseconds
- nanoseconds
输入值
- 用户需要确定如何输入持续时间值。例如,如果用户需要格式化
1000 秒,用户如何将值传递给格式化函数。
设计
- 输入值将是一个持续时间对象,包含某些受支持的持续时间单位字段的数字。
- 示例:
new DurationFormat().format({hours: 3, minutes: 4});
格式化宽度
用户希望确定以下几种格式化宽度
设计
- 用户可以使用参数
style确定格式化宽度,该参数的值可以是以下字符串之一:"long""short""narrow""digital"
- 每个字段的宽度可以在选项中单独设置,例如:
{ years: "long", months: "short", days: "narrow" }。
确定持续时间单位
DurationFormat 不会对输入进行任何算术运算或舍入。
相反,用户必须修改输入以确保输入在所需范围内。
为避免意外遗漏持续时间的一部分,DurationFormat 始终输出所有非零字段(除了由 fractionalDigits 截断的亚秒字段)。
希望省略非零字段的调用者(例如,仅显示持续时间的日期或时间部分)应编辑输入持续时间。
设计
- 持续时间存储在包含上述字段的持续时间对象中。
- 示例:
隐藏零值字段
在大多数情况下,用户希望避免显示零值字段。默认情况下,所有零值字段都被隐藏。如果您为特定字段指定了样式,则它总是被显示,但您可以通过将该特定字段的显示选项显式设置为 "auto" 来覆盖该行为。
设计
对于每个字段 foo,都有一个选项 fooDisplay,默认设置为 "auto"。将该选项设置为 "always" 会导致该字段即使为零也会被显示;例如,要始终显示 "day" 字段,设置 { dayDisplay: "always" }。如果您通过设置 foo 选项来指定该字段的样式,则 fooDisplay 的默认值变为 "always";例如,{ day: "short" } 暗示 { day: "short", dayDisplay: "always" }。
感知区域设置的格式
- 用户需要格式依赖于区域设置
- 例如:
- en-US
- 1 hour, 46 minutes and 40 seconds
- fr-FR
- 1 heure, 46 minutes et 40 secondes
- en-US
设计
将区域设置作为字符串格式的第一个参数,或将区域设置的排序列表指定为字符串数组。
显示小数值
有时希望将最小的亚秒单位不单独显示,而是作为紧邻的较大单位的分数显示。
设计
我们允许用户指定一个 fractionalDigits 选项,该选项将显示设置为 "auto" 的最小亚秒单位,如果非零且这些值的样式设置为 "numeric",则作为前一个单位的分数显示。使用的位数将是传递给此选项的值。默认情况下,fractionalDigits 是未定义的。在这种情况下,将包含恰好显示整个持续时间所需的尽可能多的小数位。如果需要舍入,我们向零舍入。
示例
API 设计
构造函数
语法
参数
locales: Array<string> | string: 区域设置字符串或按偏好递减顺序排列的区域设置字符串列表。options?: object: 用于配置实例行为的对象。它可能具有以下部分或全部属性:localeMatcher: "best fit" | "lookup": 表示使用哪种区域设置匹配算法的字符串。默认为"best fit"。numberingSystem: string: 包含用于数字格式化的编号系统名称的字符串。style: "long" | "short" | "narrow" | "digital": 用于格式化的基础样式。可以通过设置更细粒度的选项按单位覆盖。默认为"short"。years: "long" | "short" | "narrow": 用于格式化年的样式。yearsDisplay: "always" | "auto": 是否始终显示年,或仅非零时显示。months: "long" | "short" | "narrow": 用于格式化月的样式。monthsDisplay: "always" | "auto": 是否始终显示月,或仅非零时显示。weeks: "long" | "short" | "narrow": 用于格式化周的样式。weeksDisplay: "always" | "auto": 是否始终显示周,或仅非零时显示。days: "long" | "short" | "narrow": 用于格式化日的样式。daysDisplay: "always" | "auto": 是否始终显示日,或仅非零时显示。hours: "long" | "short" | "narrow" | "numeric" | "2-digit": 用于格式化小时的样式。hoursDisplay: "always" | "auto": 是否始终显示小时,或仅非零时显示。minutes: "long" | "short" | "narrow" | "numeric" | "2-digit": 用于格式化分钟的样式。minutesDisplay: "always" | "auto": 是否始终显示分钟,或仅非零时显示。seconds: "long" | "short" | "narrow" | "numeric" | "2-digit": 用于格式化秒的样式。secondsDisplay: "always" | "auto": 是否始终显示秒,或仅非零时显示。milliseconds: "long" | "short" | "narrow" | "numeric": 用于格式化毫秒的样式。millisecondsDisplay: "always" | "auto": 是否始终显示毫秒,或仅非零时显示。microseconds: "long" | "short" | "narrow" | "numeric": 用于格式化微秒的样式。microsecondsDisplay: "always" | "auto": 是否始终显示微秒,或仅非零时显示。nanoseconds: "long" | "short" | "narrow" | "numeric": 用于格式化纳秒的样式。nanosecondsDisplay: "always" | "auto": 是否始终显示纳秒,或仅非零时显示。fractionalDigits: number: 输出中显示的小数位数。 额外的小数位将被向零截断。 (Temporal.Duration.prototype.round可用于获得不同的舍入行为。) 通常此选项适用于小数秒,但实际上此选项适用于使用"numeric"或"2-digit"样式的最大秒或更小单位。 例如,如果选项是{ seconds: "narrow", milliseconds: "numeric", fractionalDigits: 4},则输出为 "12.3456 seconds"。 如果省略此选项,则仅显示非零小数,并省略尾随零。
默认值
- 对于除
"digital"之外的所有样式,每个单位的样式选项默认为style的值;对于"digital",年到日的单位默认为"short",小时到纳秒的单位默认为"numeric"。 - 如果
style为undefined,则所有值默认为"short" - 如果相应的样式选项为
undefined,则每个单位的显示选项默认为"auto",否则默认为"always"。
注意
- 某些区域设置可能在
"long"和"short"之间或"narrow"和"short"之间共享相同的表示。 其他可能使用不同的表示,例如 "3 seconds"、"3 secs"、"3s"。 - 任何样式为
"numeric"的单位,如果前面有样式为"numeric"或"2-digit"的单位,则其行为应如同使用了"2-digit"样式。 例如,{hours: 'numeric', minutes: 'numeric'}可以产生类似 "3:08" 的输出。
Intl.DurationFormat#format
语法
参数
duration(Temporal.Duration|string|object): 要格式化的持续时间。这可以是Temporal.Duration对象,也可以是可转换为一个的字符串或选项袋。
返回值
一个包含格式化持续时间的 string。
Intl.DurationFormat#formatToParts
语法
参数
duration(Temporal.Duration|string|object): 要格式化的持续时间。这可以是Temporal.Duration对象,也可以是可转换为一个的字符串或选项袋。
返回值
一个包含格式化持续时间各部分的 Array<{type: string, value: string}>。
实现状态
V8 原型
制作了三个 v8 原型(尝试使用两个不同的可能 ICU 类),所有这些都是:
- 与 "阶段 1 草案 / 2020 年 6 月 1 日" 版本的规范 同步
- 标志 --harmony_intl_duration_format
- 尚未实现 https://tc39.es/proposal-intl-duration-format/ 中尚未规范化的任何更改,例如
- hideZeroValued
- smallestUnit / largestUnit
- 基于 icu::MeasureFormat::formatMeasures()
- https://chromium-review.googlesource.com/c/v8/v8/+/2762664
- 尚未实现 formatToParts
- 需要 ICU-21543 "向 MeasureFormat 添加返回 FormattedValue 的方法" 的解决方案来实现 formatToParts()。
- 基于 LocalizedNumberFormatter 中对 "-and-" 单位的支持
- https://chromium-review.googlesource.com/c/v8/v8/+/2775300
- 尚未实现 formatToParts
- 尚未实现 style:"digital"
- 需要以下问题的解决方案来实现 formatToParts():
- 基于 icu::ListFormatter 和 icu::number::LocalizedNumberFormatter,不依赖于 "X-and-Y" 单位。
- https://chromium-review.googlesource.com/c/v8/v8/+/2776518
- 实现 formatToParts
- 尚未实现 style:"digital"