DEV Community

Omri Luz
Omri Luz

Posted on

Intl.RelativeTimeFormat for Custom Time Representations

Intl.RelativeTimeFormat in JavaScript: A Comprehensive Guide to Custom Time Representations

Introduction

Introduced in ECMAScript Internationalization API (ECMA-402) as part of ECMAScript 2020 (ES11), Intl.RelativeTimeFormat is a powerful tool for formatting time intervals relative to a specific date or time. This API allows developers to create user-friendly time representations that can vary based on culture and context, making it highly valuable in internationalization scenarios.

Historical Context of Date and Time Formatting

Historically, date and time handling in JavaScript has been cumbersome, largely due to its dependence on the Date object that offers limited internationalization support. While libraries like Moment.js and date-fns provided enhancements, they often required extensive setups and complex configurations. The ECMAScript Internationalization API was released to unify and streamline international date-time formatting, bringing native and efficient methods for developers aiming to cater to a global audience.

Technical Context of Intl.RelativeTimeFormat

The Intl.RelativeTimeFormat object is instrumental in formatting relative time strings that convey the passage of time expressed in hours, days, months, or years. The core of its API revolves around providing localized formatting to strings like ‘in 2 days’ or ‘1 month ago’.

Key Features

  • Localization: Format relative time strings based on the user's locale.
  • Units: Support for several time units: second, minute, hour, day, week, month, and year.
  • Numeric Presentation: Options for presenting time related to the current time.

Basic Syntax

const rtf = new Intl.RelativeTimeFormat('en', {
  localeMatcher: 'best fit', // Options: 'best fit' or 'lookup'
  numeric: 'auto', // Options: 'auto' or 'always'
});
Enter fullscreen mode Exit fullscreen mode

The first argument to the constructor is the locale string, while the second argument is an options object that can control the behavior of the formatting.

Core Methods

The format method is the primary method of Intl.RelativeTimeFormat:

format(value: number, unit: string): string
Enter fullscreen mode Exit fullscreen mode
  • value: An integer representing the quantity of time.
  • unit: A string that can take values such as 'second', 'minute', 'hour', 'day', 'week', 'month', 'year'.

Example of Basic Usage

const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

console.log(rtf.format(-1, 'day'));  // "yesterday"
console.log(rtf.format(2, 'month')); // "in 2 months"
console.log(rtf.format(-3, 'year')); // "3 years ago"
Enter fullscreen mode Exit fullscreen mode

Advanced Use Cases and Complex Scenarios

While the basic usage of Intl.RelativeTimeFormat covers many needs, let's delve into advanced usage scenarios.

1. Formatting for Multiple Locales

Consider a scenario where you wish to show relative time based on user preferences:

const locales = ['en', 'fr', 'es'];
const rtfInstances = locales.map(locale => new Intl.RelativeTimeFormat(locale));

const times = [
  { value: -1, unit: 'day' },         // yesterday
  { value: 1, unit: 'year' },         // in a year
  { value: -2, unit: 'month' },       // 2 months ago
];

times.forEach(time => {
  rtfInstances.forEach((rtf, index) => {
    console.log(`${locales[index]}: ${rtf.format(time.value, time.unit)}`);
  });
});
Enter fullscreen mode Exit fullscreen mode

2. Handling Edge Cases with Dynamic Dates

Consider a scenario where we need to handle dates dynamically, such as relative time from a database where timestamps are stored. Here, we can leverage Intl.RelativeTimeFormat for better user experience:

function getRelativeTime(date, locale = 'en') {
  const now = new Date();
  const timeDiff = Math.round((date - now) / (1000 * 60 * 60 * 24)); // Difference in days
  const rtf = new Intl.RelativeTimeFormat(locale);

  if (timeDiff < -1) return rtf.format(timeDiff, 'day');
  if (timeDiff > 1) return rtf.format(timeDiff, 'day');
  return rtf.format(0, 'day'); // Today
}

console.log(getRelativeTime(new Date(Date.now() - 86400000))); // "yesterday"
console.log(getRelativeTime(new Date(Date.now() + 86400000))); // "tomorrow"
Enter fullscreen mode Exit fullscreen mode

3. Numerical Customization

You can customize how numbers are displayed using the numeric option set to always, which would display ‘1 day’ instead of ‘tomorrow’:

const rtfAlways = new Intl.RelativeTimeFormat('en', { numeric: 'always' });
console.log(rtfAlways.format(-1, 'day')); // "1 day ago"
console.log(rtfAlways.format(0, 'year')); // "this year"
console.log(rtfAlways.format(1, 'hour')); // "in 1 hour"
Enter fullscreen mode Exit fullscreen mode

Performance Considerations

Memory Usage

Instantiating a single Intl.RelativeTimeFormat instance is significantly more efficient than creating new instances for every relative time format required. Reuse instances whenever possible to minimize memory overhead.

Benchmarking

Incorporating relative time formatting in high-frequency interactions (like user notifications) may necessitate benchmarking memory and processing time. Tools such as the Chrome Developer Tools Performance tab can provide insights into the operation of the formatter in real-world applications.

Batch Formatting

When dealing with repeated requests to format times in bulk, consider batching operations to optimize performance:

const relativeTimes = [
  { value: -3, unit: 'day' },
  { value: 1, unit: 'week' },
  { value: 5, unit: 'year' },
];

const rtfBatch = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });

relativeTimes.forEach(time => {
  console.log(rtfBatch.format(time.value, time.unit));
});
Enter fullscreen mode Exit fullscreen mode

This will reduce the overhead associated with instantiation during rapid calls.

Comparison with Alternative Approaches

Moment.js / Day.js

Both Moment.js and Day.js offer rich functionalities for date and time manipulation but lack the out-of-the-box support of localized relative time formatting provided by Intl.RelativeTimeFormat. In applications that require significant date manipulation, these libraries remain useful alongside the native API.

date-fns

date-fns offers modular date-time manipulation capabilities but also doesn’t directly support relative time formatting as seamlessly as Intl.RelativeTimeFormat. For developers seeking a pure JavaScript solution while still considering performance and size, using Intl.RelativeTimeFormat provides a significant advantage in terms of built-in support.

Real-World Use Cases

E-Commerce Applications

In e-commerce platforms, displaying time-sensitive promotions such as “Ends in 2 days” or “Expires in 5 hours” can be done efficiently using Intl.RelativeTimeFormat, creating urgency without cluttering user interfaces.

Social Media Platforms

Platforms like Twitter or Facebook can leverage relative time descriptions in a user-friendly manner. The ability to say "Just now" or "2 hours ago" enhances the user experience by conveying a sense of immediacy.

News Websites

News sites benefit from displaying the age of articles dynamically. Articles like "Published 5 days ago" or "Updated yesterday" can be efficiently formatted using this API for a cleaner UI.

Pitfalls and Debugging Techniques

Locale Handling Pitfalls

When implementing Intl.RelativeTimeFormat, it's critical to validate that the user's locale is supported. Some locales might not have default formats for specific time units, resulting in formatting failures.

const validateLocale = (locale) => {
  try {
    new Intl.RelativeTimeFormat(locale);
    return true;
  } catch (e) {
    console.warn(`Locale ${locale} is not supported.`);
    return false;
  }
};
Enter fullscreen mode Exit fullscreen mode

Debugging Incorrect Outputs

When facing unexpected outputs, verify both the numeric and unit values being passed. Edge cases around zero can yield strange outputs, particularly when combining units.

Use of Console for Backtracking

When developing with complex time calculations, the console can be invaluable. Take advantage of console.table() to visualize arrays of formatted outputs and raw data for better debugging.

Conclusion

The Intl.RelativeTimeFormat API is a significant advancement in formatting relative time strings in JavaScript applications, offering a native, efficient, and localized solution. The multitude of customization options and capabilities allows developers to present time in a user-friendly manner. As globalization and technology continue to advance, understanding and leveraging these tools will be essential for developers engaged in creating rich, culturally aware applications.

Further Reading

By applying the principles outlined in this guide, senior developers can enhance their applications' user experience, maintain performance efficiency, and deliver innovative functionalities that adapt to users' cultural contexts.

Top comments (0)