Relative time TypeScript helper for React
v1.0.0Added in 1.0.0
Hydration-safe timestamps for feeds and comments: "5 min. ago", day groups like Today / Yesterday, clocks and full dates.
The feed shows the same events with relative times that tick every minute, grouped under Today, Yesterday and weekday headings. Switch the locale, the style and the format in the playground to compare "5 min. ago" with "vor 5 Min.", clocks and full dates. Hover a time to see the full date.
Relative time is a Pro React helper in the React hooks and utilities category, written in TypeScript for React 19. It installs as source with npx wingo-ui@latest add relative-time, together with Date utils.
Add to a project
Requirements: React 19, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup
npx wingo-ui@latest add relative-timeRelative time is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans
Usage
Import formatTimestamp from @/lib/relative-time.
import { formatTimestamp, formatFullTimestamp, toDateTimeAttr, useNow } from "@/lib/relative-time"
export function CommentTime({ date }: { date: Date }) {
const now = useNow()
return (
<time dateTime={toDateTimeAttr(date)} title={formatFullTimestamp(date, "en-US")}>
{formatTimestamp(date, { now, locale: "en-US" })}
</time>
)
}API
localedefault"en-US"stringThe demo's locale. Every helper takes a locale; components pass the one from useLocale.
styledefault"short""long" | "short" | "narrow"RelativeTimeOptions.style: "5 minutes ago" (long) or "5 min. ago" (short).
formatdefault"relative""relative" | "time" | "date" | "datetime"TimestampOptions.format for formatTimestamp: relative text, the clock, the date or both.
groupeddefaulttruebooleanThe demo groups the feed with groupByDay.
formatTimestamp(value, options: { now: number | null; locale?: string; format?: TimestampFormat; style?; maxDays? }) => stringOne call for any row timestamp. With now null, relative falls back to "22.09.2026, 16:40".
Parts
useNow
hookThe current time rounded down to interval ms (default 60 000), re-rendering when it ticks and when the tab wakes up. null on the server and during hydration: render a date then, and relative text once it is a number. Signature: (interval?: number) => number | null.
formatRelativeTime
function"now", "5 min. ago", "3 hr. ago", "yesterday", "3 days ago", "2 wk. ago", then the date past maxDays (28). Future times read "in 5 min.", "tomorrow". Signature: (value: Date | string | number, options: { now: number; locale?: string; style?: RelativeTimeStyle; maxDays?: number; dateOptions?: Intl.DateTimeFormatOptions }) => string.
formatDayGroupLabel
function"Today", "Yesterday", "Tomorrow", a weekday within the last week ("Monday"), then the date. Signature: (value, now: number | null, locale?: string, dateOptions?) => string.
groupByDay
functionConsecutive day groups { key, date, label, items }, newest first by default; items without a valid time go last under undatedLabel ("Earlier"). Signature: <T>(items: readonly T[], getTime: (item: T) => TimeInput | null | undefined, options: { now: number | null; locale?: string; order?: "desc" | "asc" | "none"; undatedLabel?: string }) => DayGroup<T>[].
formatClock
function"4:40 PM" or "16:40"; "Thursday, September 24, 2026 at 4:40 PM" for titles; the ISO string for <time dateTime>. Signature: (value, locale?) => string.
formatFullTimestamp
function"4:40 PM" or "16:40"; "Thursday, September 24, 2026 at 4:40 PM" for titles; the ISO string for <time dateTime>. Signature: (value, locale?) => string.
toDateTimeAttr
function"4:40 PM" or "16:40"; "Thursday, September 24, 2026 at 4:40 PM" for titles; the ISO string for <time dateTime>. Signature: (value, locale?) => string.
toTime
functionParsing and calendar-day math (0 today, -1 yesterday), DST safe. Constants MINUTE, HOUR, DAY. Signature: (value) => number | null.
startOfDayTime
functionParsing and calendar-day math (0 today, -1 yesterday), DST safe. Constants MINUTE, HOUR, DAY. Signature: (time) => number.
dayDiff
functionParsing and calendar-day math (0 today, -1 yesterday), DST safe. Constants MINUTE, HOUR, DAY. Signature: (time, now) => number.
Examples
Three styles
formatRelativeTime in long, short and narrow; past maxDays (28 by default) it switches to a date.
Chat with day dividers
groupByDay with order asc gives Today, Yesterday and weekday headings; formatClock prints each message's time.
Dependencies
Files
- lib/relative-time.ts
FAQ
Is the Relative time helper free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Relative time?
Run npx wingo-ui@latest add relative-time. It also adds the Wingo UI item it builds on (Date utils). With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/relative-time.