tc39/ecma402

Intl.DurationFormat

zbraniecki opened this issue ยท 18 comments

Since there's little progress with deciding on what to do with durations, and ICU's API doesn't seem too defined about it, I'd like to start a discussion about possible choices. It seems to me that we have four:

  1. We can add it to NumberFormat
  2. We can add it to UnitFormat
  3. We can create a separate DurationFormat
  4. We can kickstart some RuleBasedNumberFormat

The common use cases are:

  1. Timer "05:12:21"
  2. Stopwatch "12:21.05"
  3. Video/Music player remaining/elapsed time "-04:13"

The formatting differs from time formatter, because the UI will define the range of units to be displayed, like h:m:s, m:s.S and the number of digits per unit (m:ss vs mm:ss or mm:ss.SSS vs mm:ss.SS)

NumberFormat would be convenient for that reason - it would benefit from similar API of defining minimumIntegerDigits and maximumIntegerDigits for each component, and the value itself may be just a number of milliseconds.

Fitting it into UnitFormat seems to be natural fit for CLDR Unit Elements [0] together with compound units, unit sequences and coordinate units, but may be hard and requiring us to bend over backward to accommodate for the options that will be required.

Custom DurationFormat seems to be the easiest choice from the API design perspective, but it increases the number of objects we specify. It's been the choice I made so far for Firefox OS patterns, but I'll be happy to migrate our code once we reach a consensus here.

RuleBasedNumberFormat is what ICU seems to be using now for duration patterns, but it's a pretty big API most similar to Mozilla's proprietary Date.prototype.toLocaleFormat and I'm not sure if we want to go there.

The API I use in DurationFormat looks like this:

var f = Intl.DurationFormat(locales, {
  minUnit: 'second', // millisecond | second | minute | hour
  maxUnit: 'hour' // millisecond | second | minute | hour
});
f.format(i); // 52:34:51

Thougths?

[0] http://www.unicode.org/reports/tr35/tr35-general.html#Unit_Elements

Brainstorming... Follow an API variation that is more parallel with DateTimeFormat for picking different field lengths:

var f = Intl.DurationFormat(locales, {
  hour: 'numeric',
  minute: '2-digit'
});
f.format(i); // 8:01

CLDR provides data for three combinations: hm (hour and minute), hms (hour, minute, and second), and ms (minute and second). AFAIK, it provides no algo for dynamically including additional fields, e.g., milliseconds. (cc @srl295?)

From those skeletons, the default length can be extracted. For example, {hm: "h:mm"} means the default for hour is numeric and the default for minutes is 2-digits.

Heads up, this has been advanced to Stage 0 as of today.

@srl295 - We will need {mm}:{ss}.{SS} at the very least for all kind of timers. (Android, iPhone timers show milliseconds). Can we get it into CLDR?

Alternatively, we could just encode a single pattern, like {hh}:{mm}:{ss}.{SS} that we "cut out" from the portion that we need.

This proposal has been advanced to Stage 1 as of today.

@zbaniecki see http://apps.icu-project.org/icu4jweb/flexTest.jsp?pat=HmsSS&_=en_US
skeleton HmsSS --> pattern HH:mm:ss.SS --> format 14:02:01.34

and in Polish HH:mm:ss,SS / 14:02:41,67

so the data / algo is there, let me know if this helps

thanks! Where is this skeleton in CLDR?

@srl295 - So I assume that flexTest indicates that it's something around the algo to get from skeleton to pattern using this: http://www.unicode.org/cldr/charts/29/summary/en.html#1746 - but I don't see anything on SS token there :( (and the value for polish is likely wrong, it should be ss.SS, not ss,SS)

@zbraniecki two problems:

  1. CLDR spec is unclear AND/OR CLDR data is incomplete.
  2. ICU has special behavior AND meta data that's not in CLDR

Filed a CLDR bug here http://unicode.org/cldr/trac/ticket/9352

@srl295, as you pointed out earlier, CLDR/ICU has support for measure format that can be used for duration format. Then, the thread moved to talk about skeletons for DateTime format.

The input to DateTime format is 'time' while the input for duration format is 'time delta'.

Can skeletons/patterns for the DateTime format be used for measure format?

@jungshik - I don't see measure format skeletons useful for duration format.

Also, CLDR bug for fractional seconds has been assigned to target CLDR 30 which should unblock us here. (http://unicode.org/cldr/trac/ticket/9352)

Are there plans to support formatToParts() for this? Seems like a natural extension, and that possibility seems to weigh on the side of having a whole separateDurationFormatter.

@icambron all new formatters will have format and formatToParts :)

sffc commented

A duplicate issue was opened at #322; see some additional discussion there.

sffc commented

A first-class Duration object is being added in Temporal. This ECMA-402 proposal for duration formatting needs to be prioritized.

sffc commented

Possible suggestion: since we are generally moving in the direction of overloading Intl constructor functionality that share similar options, I am wondering if this would be appropriate as a new method on Intl.DateTimeFormat, similar to Intl.DateTimeFormat.prototype.formatRange (CC @fabalbon).

For example,

const duration = new Temporal.Duration(...);
const fmt = new Intl.DateTimeFormat("en-US", {
  minute: "2-digit",
  second: "2-digit",
  fractionalSecondDigits: 3
});
console.log(fmt.formatDuration(duration));
// "01:23.456"
sffc commented

Update: @younies is the champion for this proposal, and will be proposing it for Stage 1 at the February TC39 meeting. The proposal repo for all further discussion is here:

https://github.com/younies/proposal-intl-duration-format