# betterdocs/4.9.5/react-src/admin/mcp/utils/format.js

BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ &amp; Chatbot, version 4.9.5. 92 lines.

- Page: https://pluginprobe.com/plugins/betterdocs/4.9.5/code/react-src/admin/mcp/utils/format.js
- Raw: https://pluginprobe.com/plugins/betterdocs/4.9.5/raw/react-src/admin/mcp/utils/format.js
- Modified: 2026-10-12T10:07:14+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/betterdocs/4.9.5/code/react-src/admin/mcp/utils/format.js#L10-L20`.

```javascript
import { __, _n, sprintf } from "@wordpress/i18n";

/**
 * Date helpers shared by the KPI tiles and the connected-apps table.
 *
 * Every timestamp this page receives is a Unix time in seconds (the pairing's
 * `connected_at` / `last_used`, each app's `created` / `last_used`), but the
 * REST layer is free to hand back a date string, so both shapes are accepted
 * and anything unparseable is treated as "no value" rather than printed as
 * `Invalid Date`.
 *
 * @since 4.9.0
 */

/**
 * A timestamp in milliseconds, or `null` when there is no usable value.
 *
 * @param {number|string|null} value Unix seconds, a parseable date string, or nothing.
 * @return {number|null} Milliseconds since the epoch, or `null`.
 */
export function toMillis(value) {
    if (!value) {
        return null;
    }
    const ts = typeof value === "number" ? value * 1000 : Date.parse(value);
    return Number.isNaN(ts) ? null : ts;
}

/**
 * A short absolute date in the reader's own locale — "Aug 20, 2026".
 *
 * The year is kept: a pairing made last year is a materially different fact
 * from one made this month, and the tile has room for four more characters.
 *
 * @param {number|string|null} value Unix seconds or a parseable date string.
 * @return {string} The formatted date, or "Never".
 */
export function formatDate(value) {
    const ts = toMillis(value);
    if (ts === null) {
        return __("Never", "betterdocs");
    }
    return new Date(ts).toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" });
}

/**
 * How long ago something happened, in words.
 *
 * Coarse on purpose: the server records one `last_used` stamp per credential
 * and no history at all, so "3 hours ago" is the whole of what is known. Past a
 * week the absolute date says more than a growing day count, so it takes over.
 *
 * @param {number|string|null} value Unix seconds or a parseable date string.
 * @param {number}             now   Milliseconds to measure from; defaults to the current time.
 * @return {string} A relative description, or "Never".
 */
export function relativeTime(value, now = Date.now()) {
    const ts = toMillis(value);
    if (ts === null) {
        return __("Never", "betterdocs");
    }

    const seconds = Math.round((now - ts) / 1000);

    // A clock skew between the server and the browser can put a stamp a few
    // seconds into the future; "in 4 seconds" would be nonsense, "Just now" is
    // both true and useful.
    if (seconds < 60) {
        return __("Just now", "betterdocs");
    }

    const minutes = Math.floor(seconds / 60);
    if (minutes < 60) {
        /* translators: %d: number of minutes. */
        return sprintf(_n("%d minute ago", "%d minutes ago", minutes, "betterdocs"), minutes);
    }

    const hours = Math.floor(minutes / 60);
    if (hours < 24) {
        /* translators: %d: number of hours. */
        return sprintf(_n("%d hour ago", "%d hours ago", hours, "betterdocs"), hours);
    }

    const days = Math.floor(hours / 24);
    if (days < 7) {
        /* translators: %d: number of days. */
        return sprintf(_n("%d day ago", "%d days ago", days, "betterdocs"), days);
    }

    return formatDate(value);
}

```
