Formatting Relative Time with JavaScript’s RelativeTimeFormat Constructor

John Au-Yeung - Feb 6 '20 - - Dev Community

Subscribe to my email list now at http://jauyeung.net/subscribe/

Follow me on Twitter at https://twitter.com/AuMayeung

Many more articles at https://medium.com/@hohanga

Even more articles at http://thewebdev.info/

With the Intl.RelativeTimeFormat constructor, we can format relative time in a locale sensitive manner with ease. We can style in different ways and format it the manner we want. This lets us format relative time strings without the hassle that comes from manipulating strings. The constructor takes 2 arguments. The first argument is a locale string or an array of such strings. The second argument is an object which takes a variety of arguments for adjusting the relative time string to the way we want. The instance of this constructor has a few methods to return the formatted string, the formatted string as an array of substrings, and a method to return the options that we set for formatting the string.

The first argument for the Intl.RelativeTimeFormat constructor is the locale which should be a BCP 47 language tag or an array of such locale strings. This is an optional argument.

The second argument accepts an object with a few properties — localeMatcher, numeric, and style .

The localeMatcher option specifies the locale matching algorithm to use. The possible values are lookup and best fit. The lookup algorithm searches for the locale until it finds the one that fits the character set of the strings that are being compared. best fit finds the locale that is at least but possibly more suited than the lookup algorithm.

The numeric option lets us set the option for how the formatted string’s message is outputted. The possible values are always which is like ‘2 days ago’, or auto , for example, like ‘yesterday’. The auto allows us to not always use numeric values for output. The style option lets us change the length of the internationalized message. The possible values are long, short, or narrow. long would output something like ‘in 2 months’, short would be something like ‘in 2 mo.’, and narrow would be something like in ‘in 2 mo.’ It could be similar to the short style in some locales.

Instances of the Intl.RelativeTimeFormat constructor have a few methods. It has the format method to get the formatted relative time string with the value and the unit according to the locale and the formatting option that’s given in the constructor. The formatToParts method is similar to the format method except that the formatted string is returned as an array instead of a string. The resolvedOptions method returns an object with the options that we set in the constructor for formatting the string and the locale that were set.

The format method takes 2 arguments. The first is the value for the quantity of the relative date and the second is the time unit in string form. For example, we can format relative dates with the format method like in the following code:

const rtf = new Intl.RelativeTimeFormat("en", {  
  localeMatcher: "best fit",  
  numeric: "always",  
  style: "long",  
});

console.log(rtf.format(-1, "day"));

The code above would log ‘1 day ago’ since we specified the value of the relative date to be -1, which means 1 day before today, and the time unit is day . We can also put in other units. For example, if we want minutes, then we get:

const rtf = new Intl.RelativeTimeFormat("en", {  
  localeMatcher: "best fit",  
  numeric: "always",  
  style: "long",  
});

console.log(rtf.format(-10, "minute"));

Then we get ‘10 minutes ago’ from the console.log statement. We can also change the style and the length. For example, we can write:

const rtf = new Intl.RelativeTimeFormat("en", {  
  localeMatcher: "best fit",  
  numeric: "auto",  
  style: "short",  
});  
console.log(rtf.format(10, "minute"));

Then we get ‘in 10 min.’ from the console.log statement since we have positive 10 instead of negative 10 which is 10 minutes from the current time. Also, we had the short style which abbreviates the unit.

We can also change the locale for different locales. For example, we can write:

const rtf = new Intl.RelativeTimeFormat("zh-hant", {  
  localeMatcher: "best fit",  
  numeric: "auto",  
  style: "long",  
});  
console.log(rtf.format(1, "minute"));

This gets the relative date-time string in Chinese Traditional characters instead of English. If we run the console.log statement in the code above, we get ‘1 分鐘後’, which means 1 minute later.

We can get the formatted string in an array of string parts with the formatToParts() method. It returns an array of substrings of the formatted strings. For example, we can call it like in the following code:

const rtf = new Intl.RelativeTimeFormat("en", {  
  localeMatcher: "best fit",  
  numeric: "always",  
  style: "long",  
});

const parts = rtf.formatToParts(-1, "day");  
console.log(parts);

The code above would get us:

[  
  {  
    "type": "integer",  
    "value": "1",  
    "unit": "day"  
  },  
  {  
    "type": "literal",  
    "value": " day ago"  
  }  
]

with the console.log statement in the code above.

The method works equally well with non-English locales. For example, we can write:

const rtf = new Intl.RelativeTimeFormat("zh-hant", {  
  localeMatcher: "best fit",  
  numeric: "auto",  
  style: "long",  
});
const parts = rtf.formatToParts(1, "minute")  
console.log(parts);

Then we get:

\[  
  {  
    "type": "integer",  
    "value": "1",  
    "unit": "minute"  
  },  
  {  
    "type": "literal",  
    "value": " 分鐘後"  
  }  
\]

with the console.log statement in the code above.

The resolvedOptions() method gets us an object with the options that we set in the constructor for formatting the string and the locale that was set. We can use it as in the following code:

const rtf = new Intl.RelativeTimeFormat("zh-hant", {  
  localeMatcher: "best fit",  
  numeric: "auto",  
  style: "long",  
});  
console.log(rtf.resolvedOptions());

With the code above, we get the following from the console.log statement:

{  
  "locale": "zh-Hant",  
  "style": "long",  
  "numeric": "auto",  
  "numberingSystem": "latn"  
}

The Intl.RelativeDateFormat constructor also has a supportedLocalesOf method to get us the supported locales for formatting date and time. It takes an array of BCP 47 locale strings as an argument. Unicode extension keys will be returned along with the locale code even though it has no relevance for date formatting if provided. It takes the localeMatcher option to specify the locale matching algorithm to use. The possible values are lookup and best fit . The lookup algorithm search for the locale until it finds the one that fits the character set of the strings that are being compared. best fit finds the locale that is at least but possibly more suited than the lookup algorithm.

For example, we can use it as in the following code:

const locales = ['en-ca', 'id-u-co-pinyin', 'ban'];  
const options = {  
  localeMatcher: 'lookup'  
};
console.log(Intl.RelativeTimeFormat.supportedLocalesOf(locales, options));

Then we get [“en-CA”, “id-u-co-pinyin”]. This is because Balinese is similar enough to Indonesian to be considered the same for the lookup algorithm. Note that the Unicode extensions that are in the input array are returned along with the output even though it has no relevance in this context.

The JavaScript Intl.RelativeTimeFormat constructor let us format relative time in a locale-sensitive manner with ease. We can style in different ways and format it the way we want. This lets us format relative time strings without much hassle that comes from manipulating strings. The constructor takes 2 arguments. The first argument is for a locale string or an array of such strings. The second is an object which takes a variety of arguments for adjusting the relative time string to the way we want. The instance of this constructor has a few methods to return the formatted string, the formatted string as an array of substrings, and a method to return the options that we set for formatting the string. We can also check the locales that supported by the static supportedLocalesOf method.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .