Want to convert date time into relative time strings like yesterday, tomorrow, 1 day ago, 1 week ago, then modern browser's native Intl is enough. Let's see how to accomplish it...
No need to use moment.js
or date-fns
or any such library. Here, we will make use of browser's native Intl
api.
const rtf = new Intl.RelativeTimeFormat('en', {
numeric: 'auto',
})
rtf.format(1, 'day') // 'tomorrow'
rtf.format(-3, 'year') // '3 years ago'
rtf.format(15, 'minute') // 'in 15 minutes'
Thus bypassing numeric value and time unit we can get the relative time string in the locale of our choice.
Instead of en
as language we can also pass navigator.language
to get the language from user's browser and present the result in that.
In the second argument supported units include: "year", "quarter", "month", "week", "day", "hour", "minute", and "second". So, here is a small function that solves this problem of what unit to pass for a given date.
/**
* Convert a date to a relative time string, such as
* "a minute ago", "in 2 hours", "yesterday", "3 months ago", etc.
* using Intl.RelativeTimeFormat
*/
export function getRelativeTimeString(date: Date | number, lang = navigator.language): string {
// Allow dates or times to be passed
const timeMs = typeof date === 'number' ? date : date.getTime()
// Get the amount of seconds between the given date and now
const deltaSeconds = Math.round((timeMs - Date.now()) / 1000)
// Array reprsenting one minute, hour, day, week, month, etc in seconds
const cutoffs = [60, 3600, 86400, 86400 * 7, 86400 * 30, 86400 * 365, Infinity]
// Array equivalent to the above but in the string representation of the units
const units: Intl.RelativeTimeFormatUnit[] = ['second', 'minute', 'hour', 'day', 'week', 'month', 'year']
// Grab the ideal cutoff unit
const unitIndex = cutoffs.findIndex((cutoff) => cutoff > Math.abs(deltaSeconds))
// Get the divisor to divide from the seconds. E.g. if our unit is "day" our divisor
// is one day in seconds, so we can divide our seconds by this to get the # of days
const divisor = unitIndex ? cutoffs[unitIndex - 1] : 1
// Intl.RelativeTimeFormat do its magic
const rtf = new Intl.RelativeTimeFormat(lang, { numeric: 'auto' })
return rtf.format(Math.floor(deltaSeconds / divisor), units[unitIndex])
}
Just pass the date in the given function and it will give the relative time from the current time.
Another good thing is that it is supported in Node.js as well so not just in browser but it can be used on server side as well.
Hope this was helpful. Thanks!!
- Ayush 🙂