One function. Three modes. Any locale.
~1.1kb gzip. zero dependencies. 200+ locales — for free.
Built entirely on native Intl. No locale files. No plugins. No config.
import { anywhen } from "anywhen";
anywhen(date);
// "yesterday, 2:35 PM" — smart mode (default)
anywhen(date, { mode: "absolute", locale: "en" });
// "Feb 5, 2016"
anywhen(date, { mode: "relative", locale: "en" });
// "3 hours ago"npm install anywhenanywhen(input);
anywhen(input, options);input is a Date, unix timestamp, or ISO string.
anywhen(new Date());
anywhen(Date.now());
anywhen("2016-02-05T14:00:00Z");The mode option picks the rendering strategy. Default is "smart".
Context-aware. Picks the most readable format based on distance from now — covers past and future.
anywhen(date, { locale: "en" });
// < 45s → "now"
// < 1 hour → "10 minutes ago"
// future > 1 hour → "in 2 weeks"
// same day → "today, 14:35"
// yesterday → "yesterday, 09:00"
// < 7 days → "Wednesday, 11:20"
// older → "Feb 5, 2016"
anywhen(date, { locale: "en", time: false });
// "yesterday" — clock removed
anywhen(date, { locale: "en", now: requestTime, timeZone: "Europe/Belgrade" });
// SSR-safe with stable anchor + timezoneReads: locale, now, time, timeZone.
Plain date formatting via Intl.DateTimeFormat. Pass format to control the
output shape.
anywhen(date, { mode: "absolute", locale: "en" });
// "Feb 5, 2016"
anywhen(date, {
mode: "absolute",
locale: "en",
format: { hour: "2-digit", minute: "2-digit" },
});
// "2:35 PM"
anywhen(date, {
mode: "absolute",
locale: "en",
format: { weekday: "long", month: "long", day: "numeric", year: "numeric" },
});
// "Friday, February 5, 2016"Reads: locale, format, timeZone.
Always relative. Past and future. Never falls back to absolute.
anywhen(date, { mode: "relative", locale: "en" });
// "3 hours ago"
// "yesterday"
// "in 2 weeks"
anywhen(date, { mode: "relative", locale: "en", numeric: true });
// "1 day ago" — disables auto-phrases like "yesterday"
// "1 week ago"Reads: locale, now, numeric.
| Option | Type | Default | Used by |
|---|---|---|---|
mode |
"smart" | "absolute" | "relative" |
"smart" |
— |
locale |
string | string[] |
runtime locale | all |
now |
Date | number | string |
current time | smart, relative |
timeZone |
string |
runtime timezone | smart, absolute |
time |
boolean |
true |
smart |
numeric |
boolean |
false |
relative |
format |
Intl.DateTimeFormatOptions |
{ day, month, year } |
absolute |
Each mode reads only the options that apply to it. The rest are ignored.
Wrap output in <time> so machines still get the exact timestamp.
import { anywhen } from "anywhen";
export function PostMeta({ createdAt }: { createdAt: string }) {
return <time dateTime={createdAt}>{anywhen(createdAt)}</time>;
}For SSR, pass now to keep server and client output stable across the
hydration boundary.
export function PostMeta({
createdAt,
requestTime,
}: {
createdAt: string;
requestTime: string;
}) {
return (
<time dateTime={createdAt}>
{anywhen(createdAt, {
locale: "en",
now: requestTime,
timeZone: "Europe/Belgrade",
})}
</time>
);
}now freezes the relative anchor. timeZone controls both the displayed
clock and the smart calendar boundaries (today, yesterday, weekday).
Pass any valid BCP 47 tag — including regional variants like en-GB, zh-TW,
pt-BR. Fallback arrays also work.
anywhen(date, { locale: "de" }); // "gestern, 14:35"
anywhen(date, { locale: "ru" }); // "вчера, 14:35"
anywhen(date, { locale: "fr" }); // "hier, 14:35"
anywhen(date, { locale: ["sr-Latn-RS", "en"] });
anywhen(date, { mode: "absolute", locale: "ja" }); // "2016年2月5日"
anywhen(date, { mode: "absolute", locale: "ar" }); // "٥ فبراير ٢٠١٦"
anywhen(date, { mode: "relative", locale: "tr" }); // "3 saat önce"When omitted, native Intl uses the runtime locale.
| anywhen | dayjs | date-fns | |
|---|---|---|---|
| gzip | ~1.1kb | ~7kb | ~20kb |
| locale data bundled | no | yes | yes |
| locales | 200+ | 140 | 100 |
| dependencies | 0 | 0 | 0 |
Node.js 13+ · Chrome 71+ · Firefox 65+ · Safari 14+ · Edge Runtime · Cloudflare Workers · Deno