Reputation: 31
I'm working on a kind of dynamic timestamp for messages using Intl
.
I want the timestamps to be dynamic in the way that it automatically transitions from ".. seconds ago" to "... minutes ago" to "... hours ago" to "today", after which it'll just return the date it's been posted. I know there's the <RelativeFormat>
component, but I want to use the API instead.
The API has a method called intl.relativeFormat
, but can't seem to figure out how to use it...
I'm a junior programmer so it's all still a bit new to me 😅😅
I appreciate your time :)
If you need more info, please let me know. I'll try to provide you with more.
Thanks!
Upvotes: 2
Views: 4918
Reputation: 127
Here is a similar idea, it also deals with future/present/past times.
function getRelativeTime(time) {
const now = new Date();
const diff = Math.abs(time - now);
const mark = (time - now) >> -1 || 1;
if (diff === 0) return new Intl.RelativeTimeFormat('en').format(0,"second");
const times = [
{ type: 'second', seconds: 1000 },
{ type: 'minute', seconds: 60 * 1000 },
{ type: 'hour', seconds: 60 * 60 * 1000 },
{ type: 'day', seconds: 24 * 60 * 60 * 1000 },
{ type: 'week', seconds: 7 * 24 * 60 * 60 * 1000 },
{ type: 'month', seconds: 30 * 24 * 60 * 60 * 1000 },
{ type: 'year', seconds: 12 * 30 * 24 * 60 * 60 * 1000 },
];
let params = [];
for (let t of times) {
const segment = Math.round(diff / t.seconds);
if (segment >= 0 && segment < 10) {
params = [(segment * mark) | 0, t.type];
break;
}
}
return new Intl.RelativeTimeFormat('en').format(...params);
}
const time = getRelativeTime(new Date(new Date().getTime() - 2 * 1000));
console.info('relative time is', time);
The function takes a time
param, finds the seconds difference relative to now, uses the array map to calculate which type yields the closest match and uses it as a param for Intl.RelativeTimeFormat
You can improve getRelativeTime(time)
function by either returning the params array and call Intl.RelativeTimeFormat
from outside the function or also pass the locale (and options) to the function.
I'm sure there are smarter ways to get rid of the times
array, perhaps by creating a wrapping closure but it will force you to "initialize" this utility function first
Upvotes: 1
Reputation: 65
Documentation for the RelativeFormat function can be found here - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat.
The idea is that you create an instance of relative time format function, with some pre-defined settings that you want the output to follow. For example, you can set your relative time format function to return English strings in a shortened format.
const rtf = new Intl.RelativeTimeFormat('en', { style: 'narrow' });
console.log(rtf.format(3, 'quarters'));
//expected output: "in 3 qtrs."
You also need to pass negative values in order to get labels intended for the past.
const rtf = new Intl.RelativeTimeFormat('en', { style: 'narrow' });
console.log(rtf.format(-3, 'quarters'));
//expected output: "3 qtrs. ago"
The next part leverages an answer given by @fearofawhackplanet here on StackOverflow
//The 'timestamp' function parameter is your timestamp passed in milliseconds.
function timeDifference(timestamp, locale) {
const msPerMinute = 60 * 1000;
const msPerHour = msPerMinute * 60;
const msPerDay = msPerHour * 24;
const msPerMonth = msPerDay * 30;
const msPerYear = msPerDay * 365;
const current = Date.now();
const elapsed = current - timestamp;
const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
if (elapsed < msPerMinute) {
return rtf.format(-Math.floor(elapsed/1000), 'seconds');
}
else if (elapsed < msPerHour) {
return rtf.format(-Math.floor(elapsed/msPerMinute), 'minutes');
}
else if (elapsed < msPerDay) {
return rtf.format(-Math.floor(elapsed/msPerHour), 'hours');
}
else {
return new Date(timestamp).toLocaleDateString(locale);
}
}
//
// code to test the above function
//
const fifteenSecondsAgo = new Date();
const tenMinutesAgo = new Date();
const twoHoursAgo = new Date();
fifteenSecondsAgo.setSeconds(fifteenSecondsAgo.getSeconds() - 15);
tenMinutesAgo.setMinutes(tenMinutesAgo.getMinutes() - 10);
twoHoursAgo.setHours(twoHoursAgo.getHours() - 2);
console.log(timeDifference(fifteenSecondsAgo.getTime(), 'en'));
console.log(timeDifference(fifteenSecondsAgo.getTime(), 'es'));
console.log(timeDifference(tenMinutesAgo.getTime(), 'en'));
console.log(timeDifference(tenMinutesAgo.getTime(), 'es'));
console.log(timeDifference(twoHoursAgo.getTime(), 'en'));
console.log(timeDifference(twoHoursAgo.getTime(), 'es'));
Here is a JSFiddle link to see the code running - https://jsfiddle.net/mhzya237/1/
Upvotes: 4