{"id":13670266,"url":"https://github.com/tc39/proposal-intl-relative-time","last_synced_at":"2025-04-27T09:32:06.996Z","repository":{"id":66133482,"uuid":"42794198","full_name":"tc39/proposal-intl-relative-time","owner":"tc39","description":"`Intl.RelativeTimeFormat` specification [draft]","archived":true,"fork":false,"pushed_at":"2020-02-20T21:02:22.000Z","size":213,"stargazers_count":215,"open_issues_count":5,"forks_count":24,"subscribers_count":38,"default_branch":"master","last_synced_at":"2024-04-13T16:45:38.114Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://tc39.github.io/proposal-intl-relative-time/","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tc39.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-09-20T00:08:02.000Z","updated_at":"2024-03-13T11:31:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"e17bc109-2612-48e5-9c71-49e68ce0116e","html_url":"https://github.com/tc39/proposal-intl-relative-time","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-intl-relative-time","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-intl-relative-time/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-intl-relative-time/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tc39%2Fproposal-intl-relative-time/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tc39","download_url":"https://codeload.github.com/tc39/proposal-intl-relative-time/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224067049,"owners_count":17250102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T09:00:37.230Z","updated_at":"2024-11-11T07:31:17.972Z","avatar_url":"https://github.com/tc39.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# `Intl.RelativeTimeFormat` API Specification [draft]\n\n## Overview\n\n### Motivation\n\nDue to common use, relative time–formatted values exist in a majority of websites and are available for the majority of frameworks (e.g., React, via [react-intl](https://github.com/yahoo/react-intl) and [react-globalize](https://github.com/globalizejs/react-globalize); Ember, via [ember-intl](https://github.com/ember-intl/ember-intl)). Popular localization libraries like [Moment.js](https://momentjs.com/), [Format.js](https://formatjs.io/), [Globalize](http://globalizejs.com/), and [others](https://github.com/rxaviers/javascript-globalization) have implemented a formatting process for relative time values as well.\n\nIt is highly probable that the majority of current relative time formatting implementations require a large portion of CLDR raw or compiled data to format relative time values. Bringing this into the platform will improve performance of the web and developer productivity as they no longer have to bring extra weight to format relative time values.\n\n### Usage examples\n\nThe following example shows how to create a relative time formatter using the English language.\n\n\u003e Units : \"year\", \"quarter\", \"month\", \"week\", \"day\", \"hour\", \"minute\" and \"second\".\n\n```js\n// Create a relative time formatter in your locale\n// with default values explicitly passed in.\nconst rtf = new Intl.RelativeTimeFormat(\"en\", {\n    localeMatcher: \"best fit\", // other values: \"lookup\"\n    numeric: \"always\", // other values: \"auto\"\n    style: \"long\", // other values: \"short\" or \"narrow\"\n});\n\n\n// Format relative time using negative value (-1).\nrtf.format(-1, \"day\");\n// \u003e \"1 day ago\"\n\n// Format relative time using positive  value (1).\nrtf.format(1, \"day\");\n// \u003e \"in 1 day\"\n\n```\n\n\u003e Note: If `numeric:auto` option is passed, it will produce the string `yesterday` or `tomorrow` instead of `1 day ago` or `in 1 day`, this allows to not always have to use numeric values in the output.\n\n```js\n// Create a relative time formatter in your locale\n// with numeric: \"auto\" option value passed in.\nconst rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n\n// Format relative time using negative value (-1).\nrtf.format(-1, \"day\");\n// \u003e \"yesterday\"\n\n// Format relative time using positive day unit (1).\nrtf.format(1, \"day\");\n// \u003e \"tomorrow\"\n```\n\n### Implementation Status\n\n__Stage 4__\n\nImplementation Progress\n\n- [V8 v7.1.179](https://bugs.chromium.org/p/v8/issues/detail?id=7869), shipped in Chrome 71\n- Shipped in Firefox 65\n- [Polyfills](#polyfills) are available\n- [Browser compatibility](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RelativeTimeFormat#Browser_compatibility)\n\nBackpointers\n\n- https://github.com/tc39/ecma402/issues/35\n\n#### Polyfills\n\nThere're several polyfills available which are listed in the comparison table below. The functionality of all polyfills is the same in terms of the API: they only differ in their implementation details like the way the polyfill is imported or the way locales are loaded or whether the implementation passes the [Official ECMAScript Conformance Test](https://github.com/tc39/test262) for the complete coverage of all possible edge cases.\n\nPolyfill | [`intl-relative-time-format`](https://www.npmjs.com/package/intl-relative-time-format) | [`@formatjs/intl-relativetimeformat`](https://www.npmjs.com/package/@formatjs/intl-relativetimeformat) | [`relative-time-format`](https://www.npmjs.com/package/relative-time-format)\n--- | --- | --- | ---\nRequirements | [Requirements](https://www.npmjs.com/package/intl-relative-time-format#dependencies--browser-support): [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat), [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules), [`Intl.getCanonicalLocales`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_ObjectsGlobal_Objects/Intl/getCanonicalLocales), `Object.is`, `WeakMap` and others | [Requirements](https://www.npmjs.com/package/@formatjs/intl-relativetimeformat#requirements): [`Intl.NumberFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat), [`Intl.PluralRules`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/PluralRules), [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) | No requirements\nCore bundle size (gzipped) | ![3.2 kB](https://img.shields.io/bundlephobia/minzip/intl-relative-time-format.svg?label=size) | ![2.7 kB](https://img.shields.io/bundlephobia/minzip/@formatjs/intl-relativetimeformat.svg?label=size)  | ![3.0 kB](https://img.shields.io/bundlephobia/minzip/relative-time-format.svg?label=size)\n| Passes the [Official ECMAScript Conformance Test](https://github.com/tc39/test262) | ✔️ [Yes](https://github.com/wessberg/intl-relative-time-format#description) | ✔️ [Yes](https://www.npmjs.com/package/@formatjs/intl-relativetimeformat#tests) | [No](https://github.com/catamphetamine/relative-time-format#test262) \n\n#### Authors\n\n- Caridy Patiño (@caridy)\n- Eric Ferraiuolo (@ericf)\n- Zibi Braniecki (@zbraniecki)\n- Rafael Xavier (@rxaviers)\n- Daniel Ehrenberg (@littledan)\n\n#### Reviewers\n\nTBD\n\n## Proposal\n\n`Intl.RelativeTimeFormat` is a low level API to facilitate libraries and frameworks to format relative time in a localized fashion by providing internationalized messages for date and time fields, using customary word or phrase when available.\n\n### Spec\n\nYou can view the [spec text](spec/relativetimeformat.html) or rendered as [HTML](https://rawgit.com/tc39/proposal-intl-relative-time/master/index.html).\n\n### Technical Design\n\nThis proposal is based on the ICU Relative Date Time Formatter and on the Unicode CLDR Calendar Fields Relative values:\n\n- http://icu-project.org/apiref/icu4j/com/ibm/icu/text/RelativeDateTimeFormatter.html\n- https://unicode.org/reports/tr35/tr35-dates.html#Calendar_Fields\n\nIt is also based on the LDML spec, C.11 Language Plural Rules:\n\n- https://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules\n\n#### Prior Art\n\n##### Java\n\n- [ICU](http://icu-project.org/apiref/icu4j/com/ibm/icu/text/RelativeDateTimeFormatter.html): `com.ibm.icu.impl.RelativeDateFormat`\n- `org.ocpsoft.prettytime.PrettyTime`\n\n##### Ruby\n\n```ruby\ninclude ActionView::Helpers::DateHelper\ndef index\n  @friendly_date = time_ago_in_words(Date.today - 1)\nend\n```\n\n#### Naming\n\nFor consistency with `Intl.NumberFormat` and `Intl.DateTimeFormat`, we have chosen a similar form for this new feature. The creation of an `Intl.RelativeTimeFormat` instance is an expensive operation that requires resolution of locale data, and most likely, libraries will attempt to cache those instances, just like they do for `Intl.NumberFormat` and `Intl.DateTimeFormat`.\n\nWe have also chosen `style` as the primary form of switching between different formatting forms for consistency with `Intl.NumberFormat` and `Intl.DateTimeFormat`.\n\nSince this new feature does format a provided value just like instances of `Intl.NumberFormat`, and `Intl.DateTimeFormat`, we have chosen the same form by providing a `format(value)` method of the instance, which returns a formatted string value.\n\n#### Take number instead of date object for input\n\nRelative time is used to display date distances, therefore the natural form of input should intuitively be a date object. Although, in this API we chose to take a number instead due to the following reasons:\n\n1. Basically, taking a number as input for the format method instead of a date object significantly simplifies the scope of this proposal while it still fully addresses the main objective which is to provide i18n building blocks to address this problem realm.\n2. Taking a date object means we should implement the comparison logic (relative time is about date distance between target and source dates). The source date is usually *now*, but not always. We would have to address modifying that. See [#4](https://github.com/tc39/proposal-intl-relative-time/issues/4).\n3. Taking a date object also means we should allow for different calendar calculations, which implies `Date` should support it. See [#6](https://github.com/tc39/proposal-intl-relative-time/issues/6) and [#13](https://github.com/tc39/proposal-intl-relative-time/issues/13).\n4. Taking a date object suggests we should be able to implement a *bestFit* algorithm, which has its own API challenges with respect to standardizing an approach that works for all cases. See [#7](https://github.com/tc39/proposal-intl-relative-time/issues/7), [#14](https://github.com/tc39/proposal-intl-relative-time/issues/14), and [#15](https://github.com/tc39/proposal-intl-relative-time/issues/15). We'd probably need to provide a flag for users to fill, with no default setting, to choose between options for calendar calculation.\n\n#### Take number as input rather than exposing the underlying database\n\nAn idea has been floated, in the context of \"the extensible web\", of just exposing the engine's copy of the CLDR database rather than a higher-level interface would be better. In the case of this specification, there is already a JS object model ready to go--the locale database is represented internally in the spec as a JavaScript object.\n\nHowever, we opted not to go that route for a couple reasons:\n- As described above, the API is already fairly low-level, taking numbers rather than dates.\n- Although there are clearly use cases for different policies about rounding dates into units, we haven't come across a use case for seeing the underlying data.\n- This new API is analogous to previous APIs, which should be useful for people learning the system.\n- CLDR changes schema over time; if the data model improves, implementations can transparently upgrade users to better results with the same API. However, if we freeze things to the current logic, the old data model would need to be emulated.\n\n#### Difference between this and `UnitFormat`\n\nThe fundamental difference between `RelativeTimeFormat` and `UnitFormat` is that `RelativeTimeFormat` displays a relative unit (e.g., `5 days ago` or `in 5 days`) while `UnitFormat` displays an absolute unit (e.g., `-5 meters` or `5 meters`). Note that `RelativeTimeFormat` uses different internationalized messages based on the value sign direction, while `UnitFormat` uses the same internationalized message for all values.\n\n##### Countdowns, e.g., 15 days, 0 hours, 27 minutes, and 52 seconds\n\nA countdown for example is a mix of `UnitFormat` and `ListFormat`, and is not a `RelativeTimeFormat`.\n\n#### NumberFormat options (e.g., useGrouping, maximumFractionDigits)\n\nRelativeTimeFormat messages may include number parts (e.g., the `1,000` in `1,000 days ago`), which are formatted using the NumberFormat default options.\n\nIn this design, we didn't find any use case that could justify allowing to change/override these NumberFormat default options. Therefore, RelativeTimeFormat doesn't include any NumberFormat option.\n\n### API\n\n#### `Intl.RelativeTimeFormat([locales[, options]])`\n\nThe `Intl.RelativeTimeFormat` object is a constructor for objects that enable language-sensitive relative time formatting.\n\n#### `locales`\n\nOptional. A string with a BCP 47 language tag, or an array of such strings. For the general form and interpretation of the `locales` argument, see the [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation).\n\n#### `options`\n\nOptional. An object with some or all of the following properties:\n\n##### `localeMatcher`\n\nThe locale matching algorithm to use. Possible values are `\"lookup\"` and `\"best fit\"`; the default is `\"best fit\"`. For information about this option, see the  [`Intl` page](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_negotiation).\n\n##### `numeric`\nThe format of output message. Possible values are  `\"always\"` (default, e.g., `1 day ago`), or `\"auto\"` (e.g., `yesterday`). `\"auto\"` allows to not always have to use numeric values in the output.\n\n##### `style`\n\nThe length of the internationalized message. Possible values are: `\"long\"` (default, e.g., `in 1 month`); `\"short\"` (e.g., `in 1 mo.`), or `\"narrow\"` (e.g., `in 1 mo.`). The narrow style could be similar to the short style for some locales.\n\n#### Example\n\n```js\n// Create a relative time formatter in your locale.\nlet rtf = new Intl.RelativeTimeFormat(\"en\", {\n    localeMatcher: \"best fit\", // other values: \"lookup\"\n    numeric: \"always\", // other values: \"auto\"\n    style: \"long\", // other values: \"short\" or \"narrow\"\n});\n```\n\n### `Intl.RelativeTimeFormat.prototype.format(value, unit)`\n\nThe `Intl.RelativeTimeFormat.prototype.format` method formats a `value` and `unit` according to the locale and formatting options of this `Intl.RelativeTimeFormat` object.\n\nWhile this method automatically provides the correct plural forms, the grammatical form is otherwise as neutral as possible. It is the caller's responsibility to handle cut-off logic such as deciding between displaying \"in 7 days\" or \"in 1 week\". This API does not support relative dates involving compound units. e.g \"in 5 days and 4 hours\".\n\n#### `value`\n\nNumeric value to use in the internationalized relative time message.\n\n#### `unit`\n\nUnit to use in the relative time internationalized message. Possible values are: `\"year\"`, `\"quarter\"`, `\"month\"`, `\"week\"`, `\"day\"`, `\"hour\"`, `\"minute\"`, `\"second\"`. Plural forms are also permitted.\n\n#### Example\n\n```js\nconst rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n\n// Format relative time using the day unit.\nrtf.format(-1, \"day\");\n// \u003e \"yesterday\"\n\nrtf.format(2.15, \"day\");\n// \u003e \"in 2.15 days\"\n\nrtf.format(100, \"day\");\n// \u003e \"in 100 days\"\n\nrtf.format(0, \"day\");\n// \u003e \"today\"\n\nrtf.format(-0, \"day\");\n// \u003e \"today\"\n```\n\nAdditionally, by combining the class option `style` and `unit`, you can achieve any of the following results:\n\n```text\nlast year\nthis year\nnext year\nin 1 year\nin 2 years\n1 year ago\n2 years ago\nyr.\nlast yr.\nthis yr.\nnext yr.\nin 1 yr.\nin 2 yr.\n1 yr. ago\n2 yr. ago\nlast quarter\nthis quarter\nnext quarter\nin 1 quarter\nin 2 quarters\n1 quarter ago\n2 quarters ago\nlast qtr.\nthis qtr.\nnext qtr.\nin 1 qtr.\nin 2 qtrs.\n1 qtr. ago\n2 qtrs. ago\nlast month\nthis month\nnext month\nin 1 month\nin 2 months\n1 month ago\n2 months ago\nlast mo.\nthis mo.\nnext mo.\nin 1 mo.\nin 2 mo.\n1 mo. ago\n2 mo. ago\nlast week\nthis week\nnext week\nin 1 week\nin 2 weeks\n1 week ago\n2 weeks ago\nlast wk.\nthis wk.\nnext wk.\nin 1 wk.\nin 2 wk.\n1 wk. ago\n2 wk. ago\nin 1 day\nin 2 days\n1 day ago\n2 days ago\nyesterday\ntoday\ntomorrow\nin 1 hour\nin 2 hours\n1 hour ago\n2 hours ago\nin 1 hr.\nin 2 hr.\n1 hr. ago\n2 hr. ago\nin 1 minute\nin 2 minutes\n1 minute ago\n2 minutes ago\nin 1 min.\nin 2 min.\n1 min. ago\n2 min. ago\nin 1 second\nin 2 seconds\n1 second ago\n2 seconds ago\nin 1 sec.\nin 1 sec.\n1 sec. ago\n2 sec. ago\nnow\n```\n\n### `Intl.RelativeTimeFormat.prototype.formatToParts(value, unit)`\n\nThe `Intl.RelativeTimeFormat.prototype.formatToParts` method is a version of the `format` method which it returns an array of objects which represent \"parts\" of the object, separating the formatted number into its consituent parts and separating it from other surrounding text. These objects have two properties: `type` a NumberFormat formatToParts type, and `value`, which is the String which is the component of the output. If a \"part\" came from NumberFormat, it will have a `unit` property which indicates the unit being formatted; literals which are part of the larger frame will not have this property.\n\n#### Example\n\n```js\nconst rtf = new Intl.RelativeTimeFormat(\"en\", { numeric: \"auto\" });\n\n// Format relative time using the day unit.\nrtf.formatToParts(-1, \"day\");\n// \u003e [{ type: \"literal\", value: \"yesterday\"}]\n\nrtf.formatToParts(100, \"day\");\n// \u003e [{ type: \"literal\", value: \"in \" }, { type: \"integer\", value: \"100\", unit: \"day\" }, { type: \"literal\", value: \" days\" }]\n```\n\n## Development\n\n### Render Spec\n\n```\nnpm install\nnpm run build\nopen index.html\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-intl-relative-time","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftc39%2Fproposal-intl-relative-time","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftc39%2Fproposal-intl-relative-time/lists"}