Relative Time

Format a date as relative time (e.g. "3 hours ago") using the native Intl.RelativeTimeFormat API. No dependencies, handles pluralization and locales automatically.

Usage

function timeAgo(date) {
  const locale = document.documentElement.lang || undefined;
  const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
  const diff = (new Date(date) - new Date()) / 1000; // seconds, negative = past

  const units = [
    ["year", 31536000],
    ["month", 2592000],
    ["week", 604800],
    ["day", 86400],
    ["hour", 3600],
    ["minute", 60],
    ["second", 1],
  ];

  for (const [unit, secs] of units) {
    if (Math.abs(diff) >= secs || unit === "second") {
      return rtf.format(Math.round(diff / secs), unit);
    }
  }
}

Web Component

Wrap the same logic in a custom element and it works from plain HTML. It re-renders every second, so a tab left open all afternoon still shows the right number, and it follows any change to the datetime attribute.

<relative-time datetime="2026-07-12T09:00:00.000Z"></relative-time>
class RelativeTime extends HTMLElement {
  static observedAttributes = ["datetime"];

  connectedCallback() {
    this.render();
    this.interval = setInterval(() => this.render(), 1000);
  }

  disconnectedCallback() {
    clearInterval(this.interval);
  }

  attributeChangedCallback() {
    this.render();
  }

  render() {
    const datetime = this.getAttribute("datetime");
    if (!datetime) return;

    const locale = document.documentElement.lang || undefined;
    const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
    const diff = (new Date(datetime) - new Date()) / 1000;

    const units = [
      ["year", 31536000],
      ["month", 2592000],
      ["week", 604800],
      ["day", 86400],
      ["hour", 3600],
      ["minute", 60],
      ["second", 1],
    ];

    for (const [unit, secs] of units) {
      if (Math.abs(diff) >= secs || unit === "second") {
        this.textContent = rtf.format(Math.round(diff / secs), unit);
        break;
      }
    }
  }
}

if (!customElements.get("relative-time")) {
  customElements.define("relative-time", RelativeTime);
}

Search 5021 icons

Type a name to find icons from the Tabler icon set.

      Move Open Esc Close