Format relative time
Intl.RelativeTimeFormat produces phrases like 3 days ago or in 2 months for any locale. You pass a signed number and a unit, and the formatter handles grammar, pluralization, and translation. This example also builds a small helper that picks the right unit from a millisecond difference.
Negative values describe the past, positive values the future.
const rtf = new Intl.RelativeTimeFormat("en", { numeric: "always" });
console.log(rtf.format(-3, "day")); // 3 days ago
console.log(rtf.format(2, "month")); // in 2 monthsWith numeric always, even a single day stays numeric.
console.log(rtf.format(-1, "day")); // 1 day ago
console.log(rtf.format(1, "day")); // in 1 dayWith numeric auto, the formatter prefers idiomatic words when they exist for the locale.
const auto = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
console.log(auto.format(-1, "day")); // yesterday
console.log(auto.format(1, "day")); // tomorrow
console.log(auto.format(0, "second")); // now
console.log(auto.format(-1, "week")); // last weekOther locales come for free.
const spanish = new Intl.RelativeTimeFormat("es", { numeric: "auto" });
console.log(spanish.format(-1, "day")); // ayer
console.log(spanish.format(2, "month")); // dentro de 2 mesesReal code usually starts from a difference between two timestamps. This helper walks from the largest unit down and uses the first unit the difference fills at least once.
const units: [Intl.RelativeTimeFormatUnit, number][] = [
["year", 365 * 24 * 60 * 60 * 1000],
["month", 30 * 24 * 60 * 60 * 1000],
["day", 24 * 60 * 60 * 1000],
["hour", 60 * 60 * 1000],
["minute", 60 * 1000],
["second", 1000],
];
function timeAgo(deltaMs: number): string {
for (const [unit, ms] of units) {
if (Math.abs(deltaMs) >= ms) {
return auto.format(Math.round(deltaMs / ms), unit);
}
}
return auto.format(0, "second");
}Fixed differences in milliseconds keep the demonstration exact.
console.log(timeAgo(-45 * 1000)); // 45 seconds ago
console.log(timeAgo(-90 * 60 * 1000)); // 1 hour ago
console.log(timeAgo(-26 * 60 * 60 * 1000)); // yesterday
console.log(timeAgo(11 * 24 * 60 * 60 * 1000)); // in 11 days
console.log(timeAgo(70 * 24 * 60 * 60 * 1000)); // in 2 monthsIn an application you would compute the difference from the clock, for example timeAgo(postDate.getTime() - Date.now()).
With Temporal, the unit math comes from the calendar instead of fixed millisecond constants: since() on zoned values yields a signed duration in the unit you ask for, ready to feed the formatter.
const now = Temporal.Instant.from("2026-06-11T12:00:00Z")
.toZonedDateTimeISO("UTC");
const earlier = Temporal.Instant.from("2026-06-08T12:00:00Z")
.toZonedDateTimeISO("UTC");
const elapsed = earlier.since(now, { largestUnit: "day" });
console.log(auto.format(elapsed.days, "day")); // 3 days agoRun this example locally using the Deno CLI:
deno run https://docs.deno.com/examples/scripts/intl_relative_time.ts