Timestamp Converter — PHP 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 PHP implementation — the same logic the interactive tool runs, in a shareable, citable form.
<?php
/**
* Unix epoch (seconds & milliseconds) <-> human forms: ISO 8601, UTC
* string, local date string, and relative time ("3 hr ago" / "in 2 day").
*
* Language: PHP
* CosmoDev polyglot showcase port of the `timestamp` tool.
* Ported from src/tools/TimestampConverter.tsx — display source, part of
* CosmoDev's polyglot tool pages.
*
* Every form derives from a single epoch-seconds value via the built-in
* DateTime class (the "@" timestamp form). relative_time() buckets
* |now - t| into sec/min/hr/day/month/yr using the same 60s / 60m / 24h /
* 30d / 365d thresholds and signs the phrase ("ago" / "in …"). now_ms is
* a parameter so the function is deterministic and unit-testable; it
* defaults to the current wall clock.
*/
declare(strict_types=1);
const INVALID = '—';
/**
* Return "3 hr ago" / "in 2 day" / "42 sec ago", mirroring the island.
*
* @param int $ms Target instant in epoch milliseconds.
* @param int|null $nowMs Reference instant ("now"); defaults to now.
*/
function relative_time(int $ms, ?int $nowMs = null): string
{
$nowMs ??= (int) (microtime(true) * 1000);
$diff = $ms - $nowMs;
$abs = abs($diff);
$sec = 1000;
$min = 60_000;
$hr = 3_600_000;
$day = 86_400_000;
if ($abs < $min) {
$n = (int) round($abs / $sec);
$unit = 'sec';
} elseif ($abs < $hr) {
$n = (int) round($abs / $min);
$unit = 'min';
} elseif ($abs < $day) {
$n = (int) round($abs / $hr);
$unit = 'hr';
} elseif ($abs < $day * 30) {
$n = (int) round($abs / $day);
$unit = 'day';
} elseif ($abs < $day * 365) {
$n = (int) round($abs / ($day * 30));
$unit = 'month';
} else {
$n = (int) round($abs / ($day * 365));
$unit = 'yr';
}
$s = "{$n} {$unit}";
return $diff < 0 ? "{$s} ago" : "in {$s}";
}
/**
* Render every form the tool exposes from epoch seconds.
*
* Matches the island's row table verbatim. "@<secs>" makes PHP interpret
* the value as UTC internally; we render ISO and the UTC string in UTC,
* and the local string in the script's default zone. Invalid instants
* (out-of-range integers) render an em dash.
*
* @return array<string,string>
*/
function format_timestamp(int $secs, ?int $nowMs = null): array
{
$dt = @DateTime::createFromFormat('U', (string) $secs);
if ($dt === false) {
return [
'Epoch (s)' => (string) $secs,
'Epoch (ms)' => (string) ($secs * 1000),
'ISO 8601' => INVALID,
'UTC' => INVALID,
'Local' => INVALID,
'Relative' => INVALID,
];
}
$utc = clone $dt;
$utc->setTimezone(new DateTimeZone('UTC'));
// Date.toISOString(): "2017-06-14T07:00:00.000Z" (ms always 000 for whole secs).
$iso = $utc->format('Y-m-d\TH:i:s.v\Z');
// toUTCString(): "Wed, 14 Jun 2017 07:00:00 GMT".
$utcStr = $utc->format('D, d M Y H:i:s') . ' GMT';
// toLocaleString() is locale-dependent; this is the default-zone form.
$local = $dt->format('Y-m-d H:i:s');
return [
'Epoch (s)' => (string) $secs,
'Epoch (ms)' => (string) ($secs * 1000),
'ISO 8601' => $iso,
'UTC' => $utcStr,
'Local' => $local,
'Relative' => relative_time($secs * 1000, $nowMs),
];
}
/**
* Parse an ISO 8601 / datetime-local ("YYYY-MM-DDTHH:mm") string into
* epoch seconds. Mirrors the island's <input type="datetime-local">
* handler: parse in the host zone and floor to seconds. Returns null for
* unparseable input (the UI silently no-ops).
*/
function from_iso(string $iso): ?int
{
$dt = DateTime::createFromFormat(DateTime::ATOM, $iso)
?: DateTime::createFromFormat('Y-m-d\TH:i', $iso)
?: DateTime::createFromFormat('Y-m-d H:i:s', $iso)
?: DateTime::createFromFormat('Y-m-d', $iso);
if ($dt === false) {
return null;
}
return (int) $dt->getTimestamp();
}
// CLI demo.
$now = (int) (microtime(true) * 1000);
foreach (format_timestamp(time(), $now) as $key => $value) {
echo str_pad($key . ':', 11) . ' ' . $value . PHP_EOL;
}
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 →