May 8, 2016

Intl.RelativeTimeFormat Spec Proposal

1RelativeTimeFormat Objects#

1.1Abstract Operations for RelativeTimeFormat Objects#

1.1.1InitializeRelativeTimeFormat (relativeTimeFormat, locales, options)#

The abstract operation InitializeRelativeTimeFormat accepts the arguments relativeTimeFormat (which must be an object), locales, and options. It initializes relativeTimeFormat as a RelativeTimeFormat object. It performas the following steps:

  1. If relativeTimeFormat has an [[InitializedIntlObject]] internal slot with value true, throw a TypeError exception.
  2. Set relativeTimeFormat.[[InitializedIntlObject]] to true.
  3. Let requestedLocales be ? CanonicalizeLocaleList(locales).
  4. If options is undefined, then
    1. Let options be ObjectCreate(%ObjectPrototype%).
  5. Else
    1. Let options be ? ToObject(options).
  6. Let opt be a new Record.
  7. Let matcher be ? GetOption(options, "localeMatcher", "string", «"lookup", "best fit"», "best fit").
  8. Set opt.[[LocaleMatcher]] to matcher.
  9. Let localeData be %RelativeTimeFormat%.[[LocaleData]].
  10. Let r be ResolveLocale(%RelativeTimeFormat%.[[AvailableLocales]], requestedLocales, opt, %RelativeTimeFormat%.[[RelevantExtensionKeys]], localeData).
  11. Set relativeTimeFormat.[[Locale]] to the value of r.[[Locale]].
  12. Let dataLocale be r.[[DataLocale]].
  13. Let s be ? GetOption(options, "style", "string", «"long", "short", "narrow"», "long").
  14. Set relativeTimeFormat.[[Style]] to s.
  15. Let u be ? GetOption(options, "unit", "string", «"best fit", "second", "minute", "hour", "day", "week", "month", "quarter", "year"», "best fit").
  16. Set relativeTimeFormat.[[Unit]] to u.
  17. Let dataLocaleData be Get(localeData, dataLocale).
  18. Let fields be Get(dataLocaleData, "fields").
  19. Assert: fields is an object (see 1.3.3).
  20. Set relativeTimeFormat.[[Fields]] to fields.
  21. Let nfLocale be CreateArrayFromListlocale »).
  22. Let nfOptions be ObjectCreate(%ObjectPrototype%).
  23. Perform ! CreateDataPropertyOrThrow(nfOptions, "useGrouping", false).
  24. Perform ! CreateDataPropertyOrThrow(nfOptions, "minimumIntegerDigits", 2).
  25. Let relativeTimeFormat.[[NumberFormat]] be ? Construct(%NumberFormat%, « nfLocale, nfOptions »).
  26. Let prLocale be CreateArrayFromListlocale »).
  27. Let prOptions be ObjectCreate(%ObjectPrototype%).
  28. Perform ! CreateDataPropertyOrThrow(prOptions, "style", "cardinal").
  29. Let relativeTimeFormat.[[PluralRules]] be ? Construct(%PluralRules%, « prLocale, prOptions »).
  30. Set relativeTimeFormat.[[InitializedRelativeTimeFormat]] to true.
  31. Return relativeTimeFormat.

1.1.2PartitionRelativeTimePattern (relativeTimeFormat, x)#

When the FormatRelativeTime abstract operation is called with arguments relativeTimeFormat and value, it returns a String value representing value (interpreted as a time value as specified in ES2016, 20.3.1.1) according to the effective locale and the formatting options of relativeTimeFormat.

  1. Assert: relativeTimeFormat.[[InitializedRelativeTimeFormat]] is true.
  2. Assert: Type(value) is a Number.
  3. If isFinite(x) is false, then throw a RangeError exception.
  4. Let fields be relativeTimeFormat.[[Fields]].
  5. Let style be relativeTimeFormat.[[Style]].
  6. Let now be Call(%Date_now%, undefined).
  7. Let ms be x - now.
  8. Let units be ComputeTimeUnits(ms).
  9. If relativeTimeFormat.[[Unit]] is equal to "best fit", then
    1. Let unit be GetBestMatchUnit(units).
  10. Else
    1. Let unit be relativeTimeFormat.[[unit]].
  11. If style is equal to "short", then
    1. Let entry be unit + "-short".
  12. Else if style is equal to "narrow", then
    1. Let entry be unit + "-narrow".
  13. Else
    1. Let entry be unit.
  14. Let exists be ? HasProperty(fields, entry).
  15. If exists is false, then
    1. Let entry be unit.
  16. Let patterns be ? Get(fields, entry).
  17. Let v be units.[[<unit>]].
  18. If v is between -2 (inclusive) and 2 (inclusive), then
    1. Let exists be ? HasProperty(patterns, ToString(v)).
    2. If exists is true, then
      1. Let result be Get(patterns, ToString(v)).
      2. Return result.
  19. If v is less than 0, then
    1. Let tl be "past".
  20. Else
    1. Let tl be "future".
  21. Let po be ? Get(patterns, tl).
  22. Let fv be ! FormatNumber(relativeTimeFormat.[[NumberFormat]], v).
  23. Let pr be ! ResolvePlural(relativeTimeFormat.[[PluralRules]], v).
  24. Let pattern be ? Get(po, pr).
  25. Let values be a new Record.
  26. Set values.[["0"]] to be new Record { [[Type]]: "number", [[Value]]: fv }.
  27. Return ? DeconstructPattern(pattern, values).

1.1.3DeconstructPattern (pattern, placeables)#

The DeconstructPattern abstract operation is called with arguments pattern (which must be a String) and placeables (which must be a Record), and deconstructts the pattern string into a list of parts. Example:

        Input:
          DeconstructPattern("AA{xx}BB{yy}CC", {
            xx: {type: 'hour', value: '15'},
            yy: {type: 'minute', value: '06'}
          });

        Output (List of Records):
          [
            {type: 'literal', value: 'AA'},
            {type: 'hour', value: '15'},
            {type: 'literal', value: 'BB'},
            {type: 'minute', value: '06'},
            {type: 'literal', value: 'CC'}
          ]
        

  1. Set parts to be the result of pattern.split(/\{([^\}]+)\}/).
  2. Let result be a new empty List.
  3. Set i to be 0.
  4. Repeat, while i < parts.length
    1. Set part to be parts.[i].
    2. If i % 2 is 0, then
      1. If part.length is > 0, then
        1. Add new part record { [[type]]: "literal", [[value]]: part } as a new element on the list result.
    3. Else,
      1. Set subst to placeables.[[part]].
      2. If subst is undefined, then
        1. Throw new Error exception.
      3. If Type(subst) is List, then
        1. Let len be ? ToLength(? Get(subst, "length")).
        2. Set i to 0.
        3. Repeat, while i < 0
          1. Add subst.[i] as a new element on the list result.
      4. Else,
        1. Add subst as a new element on the list result.
  5. Return result.

1.1.4FormatRelativeTime (relativeTimeFormat, x)#

The FormatRelativeTime abstract operation is called with arguments relativeTimeFormat (which must be an object initialized as a RelativeTimeFormat) and x (which must be a Number value), and performs the following steps:

  1. Let parts be ? PartitionRelativeTimePattern(relativeTimeFormat, x).
  2. Let result be an empty String.
  3. For each part in parts, do:
    1. Set result to a String value produced by concatenating result and part.[[Value]].
  4. Return result.

1.1.5FormatRelativeTimeToParts (relativeTimeFormat, x)#

The FormatRelativeTimeToParts abstract operation is called with arguments relativeTimeFormat (which must be an object initialized as a RelativeTimeFormat) and x (which must be a Number value), and performs the following steps:

  1. Let parts be ? PartitionRelativeTimePattern(relativeTimeFormat, x).
  2. Let result be ArrayCreate(0).
  3. Let n be 0.
  4. For each part in parts, do:
    1. Let O be ObjectCreate(%ObjectPrototype%).
    2. Perform ? CreateDataPropertyOrThrow(O, "type", part.[[Type]]).
    3. Perform ? CreateDataPropertyOrThrow(O, "value", part.[[Value]]).
    4. Perform ? CreateDataProperty(result, ? ToString(n), O).
    5. Increment n by 1.
  5. Return result.

1.1.6GetBestMatchUnit (units)#

When the GetBestMatchUnit abstract operation is called with argument units, the following steps are taken:

  1. Assert: Type(units) is a Record.
  2. If units.[[Second]] is less than 60, return "Second".
  3. If units.[[Minute]] is less than 60, return "Minute".
  4. If units.[[Hour]] is less than 24, return "Hour".
  5. If units.[[Day]] is less than 7, return "Day".
  6. If units.[[Week]] is less than 4, return "Week".
  7. If units.[[Month]] is less than 12, return "Month".
  8. If units.[[Quarter]] is less than 4, return "Quarter".
  9. Return "Year".
Note It is recommended that implementations use the locale and relative time dependent strings provided by the Common Locale Data Repository (available at http://cldr.unicode.org/).

1.1.7ComputeTimeUnits (v)#

When the ComputeTimeUnits abstract operation is called with argument v, the following steps are taken:

  1. Assert: v is a Number.
  2. Let units be ObjectCreate(%ObjectPrototype%).
  3. Let rawYear be v * 400 / msPer400Years.
  4. Set units.[[Second]] to round(v / msPerSecond).
  5. Set units.[[Minute]] to round(v / msPerMinute).
  6. Set units.[[Hour]] to round(v / msPerHour).
  7. Set units.[[Day]] to round(v / msPerDay).
  8. Set units.[[Week]] to round(v / msPerWeek).
  9. Set units.[[Month]] to round(rawYear * 12).
  10. Set units.[[Quarter]] to round(rawYear * 4).
  11. Set units.[[Year]] to round(rawYear).
  12. Return units.

where

msPerWeek = 604800000 = msPerDay × DaysPerWeek
msPer400Years = 88359465600000 = msPerDay × 146097
Note 400 years have 146097 days when taking into account the leap year rules. We can not take into consideration the timeline for the leap years because the relativeness of v is not implicit in this abtract operation.

1.2The Intl.RelativeTimeFormat Constructor#

The RelativeTimeFormat constructor is a standard built-in property of the Intl object. Behaviour common to all service constructor properties of the Intl object is specified in .

1.2.1Intl.RelativeTimeFormat ([ locales [ , options ]])#

When the Intl.RelativeTimeFormat function is called with optional arguments the following steps are taken:

  1. If NewTarget is undefined, let newTarget be the active function object, else let newTarget be NewTarget.
  2. Let relativeTimeFormat be ? OrdinaryCreateFromConstructor(newTarget, %RelativeTimeFormatPrototype%).
  3. Return ? InitializeRelativeTimeFormat(relativeTimeFormat, locales, options).

1.3Properties of the Intl.RelativeTimeFormat Constructor#

The Intl.RelativeTimeFormat constructor has the following properties:

1.3.1Intl.RelativeTimeFormat.prototype#

The value of Intl.RelativeTimeFormat.prototype is %RelativeTimeFormatPrototype%.

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.

1.3.2Intl.RelativeTimeFormat.supportedLocalesOf (locales [, options ])#

When the supportedLocalesOf method of %RelativeTimeFormat% is called, the following steps are taken:

  1. Let availableLocales be %RelativeTimeFormat%.[[availableLocales]].
  2. Let requestedLocales be CanonicalizeLocaleList(locales).
  3. Return SupportedLocales(availableLocales, requestedLocales, options).

The value of the length property of the supportedLocalesOf method is 1.

1.3.3Internal slots#

The value of the [[AvailableLocales]] internal slot is implementation defined within the constraints described in .

The value of the [[RelevantExtensionKeys]] internal slot is ["rt", "pr"].

Note 1 Unicode Technical Standard 35 describes three locale extension keys that are relevant to relative time formatting, "rt" for relative time, and "pr" language plural rules to choose the proper relative time pattern.

The value of the [[LocaleData]] internal slot is implementation defined within the constraints described in and the following additional constraints:

  • [[LocaleData]][Locale] must have a pluralRules property for all locale values. The value of this property must be an object, which must have a property oridinal, which must be a function. These function expect a numeric argument and the return must be string value "zero", "one", "two", "few", "many" or "other". The returned string represents the pluralization form of the numeric argument as specified in LDML Language Plural Rules.
  • [[LocaleData]][Locale] must have a fields property for all locale values. The value of this property must be an object, which must have properties second, minute, hour, day, week, month, quarter and year, additionally, it can have the equivalent properties for narrow and short. Each of these properties in turn must be an object, whose value contains future and past pluralization rules, and optionally, it can have unitary representations.
Note 2 It is recommended that implementations use the locale data provided by the Common Locale Data Repository (available at http://cldr.unicode.org/).

1.4Properties of the Intl.RelativeTimeFormat Prototype Object#

The Intl.RelativeTimeFormat prototype object is itself an Intl.RelativeTimeFormat instance as specified in 1.5, whose internal slots are set as if it had been constructed by the expression Construct(%RelativeTimeFormat%).

In the following descriptions of functions that are properties or [[Get]] attributes of properties of %RelativeTimeFormatPrototype%, the phrase "this RelativeTimeFormat object" refers to the object that is the this value for the invocation of the function; a TypeError exception is thrown if the this value is not an object or an object that does not have an [[initializedRelativeTimeFormat]] internal slot with value true.

1.4.1Intl.RelativeTimeFormat.prototype.constructor#

The initial value of Intl.RelativeTimeFormat.prototype.constructor is %RelativeTimeFormat%.

1.4.2Intl.RelativeTimeFormat.prototype[ @@toStringTag ]#

The initial value of the @@toStringTag property is the string value "Object".

This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true }.

1.4.3Intl.RelativeTimeFormat.prototype.format([ value ])#

When the Intl.RelativeTimeFormat.prototype.format is called with an optional argument value, the following steps are taken:

  1. Let relativeTimeFormat be this value.
  2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not have an [[InitializedRelativeTimeFormat]] internal slot whose value is true, throw a TypeError exception.
  3. If value is not provided, let value be undefined.
  4. Let value be ? ToNumber(value).
  5. Return ? FormatRelativeTime(relativeTimeFormat, value).

1.4.4Intl.RelativeTimeFormat.prototype.formatToParts([ value ])#

When the Intl.RelativeTimeFormat.prototype.formatToParts is called with an optional argument value, the following steps are taken:

  1. Let relativeTimeFormat be this value.
  2. If Type(relativeTimeFormat) is not Object or relativeTimeFormat does not have an [[InitializedRelativeTimeFormat]] internal slot whose value is true, throw a TypeError exception.
  3. If value is not provided, let value be undefined.
  4. Let value be ? ToNumber(value).
  5. Return ? FormatRelativeTimeToParts(relativeTimeFormat, value).

1.4.5Intl.RelativeTimeFormat.prototype.resolvedOptions ()#

This function provides access to the locale and formatting options computed during initialization of the object.

The function returns a new object whose properties and attributes are set as if constructed by an object literal assigning to each of the following properties the value of the corresponding internal slot of this RelativeTimeFormat object (see 1.5): locale, style and unit. Properties whose corresponding internal slots are not present are not assigned.

1.5Properties of Intl.RelativeTimeFormat Instances#

Intl.RelativeTimeFormat instances inherit properties from %RelativeTimeFormatPrototype%.

Intl.RelativeTimeFormat instances and other objects that have been successfully initialized as a RelativeTimeFormat have [[InitializedIntlObject]] and [[InitializedRelativeTimeFormat]] internal slots whose values are true.

Objects that have been successfully initialized as a RelativeTimeFormat object also have several internal slots that are computed by the constructor:

  • [[Locale]] is a String value with the language tag of the locale whose localization is used for formatting.
  • [[Style]] is one of the String values "long", "short", or "narrow", identifying the relative time format style used.
  • [[Unit]] is one of the String values "best fit", "second", "minute", "hour", "day", "week", "month", "quarter" or "year", identifying the unit of time used.