Relative Time

Renders a DateTime or Date relative to now, such as "3 minutes ago" or "yesterday", in a <time> element.

Read more Read less

Maturity: Developing

Usage

The server renders the absolute value. The browser replaces it with the relative text in the page's language, which requires calling relativeTimes() from @woylie/doggo in your app.js. Without JavaScript, the absolute value remains.

<.relative_time value={@post.inserted_at} />

The text is converted once. Set sync to keep it up to date while the page is open:

<.relative_time value={@message.sent_at} sync />

Past a threshold, the absolute value is shown instead. With localize, the absolute value is in the user's format:

<.relative_time
  value={@event.starts_at}
  threshold={Duration.new!(week: 1)}
  localize={:medium}
/>

The title contains the absolute value.

A Date is compared by calendar day, so the text reads "yesterday" or "in 2 days".

To stop the relative times inside an element from updating, for example as a user setting, set data-relative-sync="false" on that element. It overrides sync.

VoiceOver on macOS announces the element as a group named by the title, then reads the text and the title again. Without JavaScript, past the threshold and when printing, the text is the absolute value. Orca reads the default ISO 8601 text as separate numbers and dashes. VoiceOver reads it as a date, but not a date with slashes such as 2/5/23, which localize={:short} writes in some locales. To write the month as a word, set localize to :long, or pass a formatter that uses the locale data of your application. Only a formatter changes the text for users without JavaScript.

Hover over a value to see the absolute value in the title.

<.relative_time value={~U[2026-10-02 22:09:45.495826Z]} />
<.relative_time value={~U[2026-10-02 22:05:05.495826Z]} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} />
<.relative_time value={~U[2026-09-29 22:10:05.495826Z]} />
<.relative_time value={~U[2026-10-02 22:20:05.495826Z]} />

A Date is compared by calendar day.

<.relative_time value={~D[2026-10-01]} />
<.relative_time value={~D[2026-10-04]} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} format={:long} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} format={:short} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} format={:narrow} />

:always never writes words such as "yesterday".

<.relative_time value={~U[2026-10-01 22:10:05.495826Z]} numeric={:auto} />
<.relative_time value={~U[2026-10-01 22:10:05.495826Z]} numeric={:always} />

The first value is converted once, the second keeps counting while the page is open.

<.relative_time value={~U[2026-10-02 22:09:15.495826Z]} />
<.relative_time value={~U[2026-10-02 22:09:15.495826Z]} sync />

Past a threshold of one day, the second value shows the absolute value in the user's format.

<.relative_time
  value={~U[2026-10-02 19:10:05.495826Z]}
  threshold={%Duration{day: 1}}
  localize={:medium}
 />
<.relative_time
  value={~U[2026-09-29 22:10:05.495826Z]}
  threshold={%Duration{day: 1}}
  localize={:medium}
 />

Hover to see the title. The first value has the server's text, the second the title: style, and the third the title: pattern.

<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} localize={[title: :full]} />
<.relative_time value={~U[2026-10-02 19:10:05.495826Z]} localize={[title: "%Y-%m-%d %H:%M"]} />