# Relative time

> Hydration-safe timestamps for feeds and comments: "5 min. ago", day groups like Today / Yesterday, clocks and full dates.

- Type: React helper (Hooks & Utilities)
- Access: Pro (the source needs a Wingo UI Pro plan, see https://wingo-ui.com/pricing)
- Version: 1.0.0
- Install: `npx wingo-ui@latest add relative-time`
- Docs: https://wingo-ui.com/components/relative-time

## Interaction

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.

## Installation

```bash
npx wingo-ui@latest add relative-time
```

Pro item: run `npx wingo-ui@latest login` once with a Pro account. The CLI adds the files, their dependencies and a version record for updates.

With shadcn: `npx shadcn@latest add @wingo-ui/relative-time` (needs the @wingo-ui registry with your API key in components.json)

Files:

- `lib/relative-time.ts`

Wingo UI dependencies (installed automatically):

- [Date utils](https://wingo-ui.com/components/date-utils) ([Markdown](https://wingo-ui.com/components/date-utils.md))

## Usage

```tsx
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

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `locale?` | `string` | `"en-US"` | The demo's locale. Every helper takes a locale; components pass the one from useLocale. |
| `style?` | `"long" \| "short" \| "narrow"` | `"short"` | RelativeTimeOptions.style: "5 minutes ago" (long) or "5 min. ago" (short). |
| `format?` | `"relative" \| "time" \| "date" \| "datetime"` | `"relative"` | TimestampOptions.format for formatTimestamp: relative text, the clock, the date or both. |
| `grouped?` | `boolean` | `true` | The demo groups the feed with groupByDay. |
| `formatTimestamp?` | `(value, options: { now: number \| null; locale?: string; format?: TimestampFormat; style?; maxDays? }) => string` |  | One call for any row timestamp. With now null, relative falls back to "22.09.2026, 16:40". |

## Parts

### useNow (hook)

The 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 (function)

Consecutive 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 (function)

Parsing and calendar-day math (0 today, -1 yesterday), DST safe. Constants MINUTE, HOUR, DAY. Signature: (value) => number | null.

### startOfDayTime (function)

Parsing and calendar-day math (0 today, -1 yesterday), DST safe. Constants MINUTE, HOUR, DAY. Signature: (time) => number.

### dayDiff (function)

Parsing 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.

## See also

- [Date utils](https://wingo-ui.com/components/date-utils) ([Markdown](https://wingo-ui.com/components/date-utils.md))
- [useLocale](https://wingo-ui.com/components/use-locale) ([Markdown](https://wingo-ui.com/components/use-locale.md))
- [Number format](https://wingo-ui.com/components/number-format) ([Markdown](https://wingo-ui.com/components/number-format.md))

---

Canonical: https://wingo-ui.com/components/relative-time
More components: https://wingo-ui.com/components · Index for agents: https://wingo-ui.com/llms.txt
