Timestamp Converter — JavaScript source
Convert Unix epoch timestamps to human-readable dates and back. See seconds, milliseconds, ISO 8601, UTC, local and relative time at once.
This is the JavaScript implementation — the same logic the interactive tool runs, in a shareable, citable form.
/**
* Unix epoch (seconds & milliseconds) <-> human forms: ISO 8601, UTC
* string, local date string, and relative time ("3 hr ago" / "in 2 day").
*
* Language: JavaScript (ES module)
* CosmoDev polyglot showcase port of the `timestamp` tool.
* Ported from src/tools/TimestampConverter.tsx - display source, part of
* CosmoDev's polyglot tool pages.
*
* The island's pure logic, extracted without JSX or React state: every
* form derives from a single epoch-seconds value via the standard Date.
* relativeTime() buckets |now - t| into sec/min/hr/day/month/yr using the
* same 60s / 60m / 24h / 30d / 365d thresholds, rounds to the nearest unit,
* and signs the phrase ("ago" vs "in …"). nowMs is a parameter so the
* function is deterministic and unit-testable; it defaults to Date.now().
*/
/** Em dash used by the UI for invalid instants. */
const INVALID = '-';
/** True when epoch-seconds resolve to a real instant (not NaN/Infinity). */
export function isValid(secs) {
return Number.isFinite(new Date(secs * 1000).getTime());
}
/**
* Human-readable relative time, mirroring the island exactly.
*
* @param ms Target instant in epoch milliseconds.
* @param nowMs Reference instant ("now"); defaults to Date.now().
* @returns "42 sec ago", "in 3 hr", "2 day ago", etc.
*/
export function relativeTime(ms, nowMs = Date.now()) {
const diff = ms - nowMs;
const abs = Math.abs(diff);
const min = 60_000;
const hr = 3_600_000;
const day = 86_400_000;
let n, unit;
if (abs < min) {
n = Math.round(abs / 1000);
unit = 'sec';
} else if (abs < hr) {
n = Math.round(abs / min);
unit = 'min';
} else if (abs < day) {
n = Math.round(abs / hr);
unit = 'hr';
} else if (abs < day * 30) {
n = Math.round(abs / day);
unit = 'day';
} else if (abs < day * 365) {
n = Math.round(abs / (day * 30));
unit = 'month';
} else {
n = Math.round(abs / (day * 365));
unit = 'yr';
}
const s = `${n} ${unit}`;
return diff < 0 ? `${s} ago` : `in ${s}`;
}
/**
* Render every form the tool exposes from a single epoch-seconds value.
*
* Matches the island's row table verbatim: epoch (s), epoch (ms), ISO 8601,
* UTC (Date.toUTCString), local (Date.toLocaleString), and relative time.
* Invalid instants render an em dash, exactly like the live UI.
*/
export function formatTimestamp(secs, nowMs = Date.now()) {
const ms = secs * 1000;
const date = new Date(ms);
const ok = Number.isFinite(date.getTime());
return {
epochSeconds: String(secs),
epochMillis: String(ms),
iso8601: ok ? date.toISOString() : INVALID,
utc: ok ? date.toUTCString() : INVALID,
local: ok ? date.toLocaleString() : INVALID,
relative: relativeTime(ms, nowMs),
};
}
/**
* Parse an ISO 8601 / datetime-local ("YYYY-MM-DDTHH:mm") string into
* epoch seconds. Mirrors the island's <input type="datetime-local">
* handler: feed the string to the Date constructor and floor to seconds.
* Returns null for unparseable input (the UI silently no-ops).
*/
export function fromISO(iso) {
const t = new Date(iso).getTime();
return Number.isFinite(t) ? Math.floor(t / 1000) : null;
}
/**
* Render the local "YYYY-MM-DDTHH:mm" value used to seed a
* datetime-local input so the user can edit the instant in their own
* timezone - the same offset trick the island uses.
*/
export function toLocalInput(secs) {
const d = new Date(secs * 1000 - new Date().getTimezoneOffset() * 60000);
return d.toISOString().slice(0, 16);
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →