Show Yesterday, Today, and Tomorrow Labels in JavaScript
To show word labels like 'yesterday' and 'tomorrow', use Intl.RelativeTimeFormat(locale, { numeric: 'auto' }) and pass the day difference computed in the user's zone. Part of Intl.RelativeTimeFormat for Relative Dates.
Why this scenario is tricky
Two things make this deceptively easy to break: the day difference must be counted in calendar days in the user's zone, not by dividing a millisecond gap (which flips at the wrong moment), and the friendly words only appear when you set numeric: 'auto' — the default 'always' prints '1 day ago' instead of 'yesterday'.
Minimal working solution
import { Temporal } from '@js-temporal/polyfill';
const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' });
const days = today.until(target, { largestUnit: 'day' }).days; // both PlainDate in user's zone
rtf.format(days, 'day'); // -1 -> 'yesterday', 0 -> 'today', 1 -> 'tomorrow'
Full production version
import { Temporal } from '@js-temporal/polyfill';
function dayLabel(target: Temporal.PlainDate, zone: string, locale = 'en'): string {
const today = Temporal.Now.plainDateISO(zone);
const days = today.until(target, { largestUnit: 'day' }).days;
return new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(days, 'day');
}
Verification snippet
Common pitfalls
Frequently Asked Questions
How do I show 'yesterday' and 'tomorrow' instead of '1 day ago'?
Create Intl.RelativeTimeFormat with numeric: 'auto' and pass the signed day difference. With 'auto', values of -1, 0, and 1 render as 'yesterday', 'today', and 'tomorrow'; the default 'always' would print '1 day ago' and 'in 1 day'.
How do I compute the day difference correctly?
Count whole calendar days in the user's time zone, for example with Temporal.PlainDate.until(target, { largestUnit: 'day' }).days where both dates are PlainDates in that zone. Dividing a millisecond gap by 86,400,000 flips at the wrong moment near midnight.