Skip to main content
Search
Search the documentation

Relative time

Timestamps like 5 minutes ago that stay true, in the reader's language, without a timer per second.

pnpm dlx shadcn-svelte@latest add https://coral.imlargo.dev/r/kit-relative-time.json

relativeTime(date) helpers get written once per project, and they share the same limits: the text is computed at render and goes stale while the page is open, "60 minutes ago" shows up where "1 hour ago" belongs, and the fix (a setInterval per timestamp) wakes a two-hundred-row table every second to change nothing.

  • Build passed
  • Deployed to production
  • Issue closed
  • API key rotated
  • Maintenance window

What Coral adds

  • Stays current, cheaply. Each instance sleeps until the exact moment its own text changes: "3 days ago" wakes up in hours, not every second. A tab brought back to the foreground refreshes at once, since background timers are throttled.
  • Right units: the unit is picked on the rounded value, so 59 minutes 40 seconds is "1 hour ago". Four weeks never sits next to one month.
  • Worded by Intl. "yesterday", "in 3 days", "hace 5 minutos", "5 分前": any locale, in long, short or narrow.
  • A real <time>: datetime carries the instant for machines and title the full date for whoever hovers.
  • Symmetric. 2.5 minutes ago and in 2.5 minutes both round to 3.

Live

You opened this page .

Short form:

precision="minute", the default, reads anything within half a minute as "now", since a label ticking every second draws the eye for no reason. Use second where the seconds matter.

Past a cutoff

  • 2 days ago
  • 40 days ago

"40 days ago" is rarely what anyone wants to read about a deployment. Past cutoff milliseconds the date is shown in full instead, formatted with titleFormat, and nothing is scheduled for it.

Import

<script lang="ts">
	import RelativeTime from '#lib/components/coral/kit/relative-time/relative-time.svelte';
</script>

Props

Everything a <time> accepts stays available: class, aria-*, id. On top of that:

PropTypeDefaultDescription
dateDate | string | number-The moment to describe. Required.
localestringen-USWording and absolute date.
numeric'auto' | 'always'auto"yesterday" versus "1 day ago".
format'long' | 'short' | 'narrow'longLength of the wording.
precision'second' | 'minute'minuteSmallest unit shown.
livebooleantrueKeeps the text current.
cutoffnumber-Milliseconds past which the full date shows.
titleFormatIntl.DateTimeFormatOptions{ dateStyle: 'long', timeStyle: 'short' }The absolute date's format.
nowDate-Pins the clock - tests, previews, snapshots.
childrenSnippet<[{ text, absolute, date }]>-Replaces the text inside <time>.

relative.ts

describe and nextChange are exported for use outside a component, such as a label in an email or a server-rendered feed:

import { describe } from '#lib/components/coral/kit/relative-time/relative.js';

const { value, unit } = describe(new Date(comment.createdAt), new Date());
// `undefined` is the reader's own locale; pass one to pin it.
new Intl.RelativeTimeFormat(undefined, { numeric: 'auto' }).format(value, unit); // "5 minutes ago"

Months and years are average lengths, so a relative label is approximate by nature. For "on 12 March", use the absolute date.