epochkit: Unix Timestamps With Timezone Sanity and Saved Favorites
Debugging webhook logs across UTC and local. Converter plus localStorage favorites for the five API environments I juggle daily.
Problem: Log line said 1714521600. Is that seconds or milliseconds? Built a tool that detects both and remembers my staging server offset.
Full tool
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Timestamp Converter</title>
<style>
body { font-family: system-ui; max-width: 640px; margin: 2rem auto; padding: 0 1rem; }
input { width: 100%; padding: .5rem; font-family: monospace; margin: .25rem 0; }
.grid { display: grid; gap: .75rem; }
.fav { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: 1rem; }
.fav button { font-size: 12px; }
</style>
</head>
<body>
<h1>Timestamp Converter</h1>
<div class="grid">
<label>Unix timestamp <input id="ts" placeholder="1714521600"></label>
<label>ISO / local <input id="iso" placeholder="2024-05-01T00:00:00"></label>
<label>Human <output id="human"></output></label>
</div>
<button id="now">Now</button>
<button id="save">Save favorite</button>
<div class="fav" id="favs"></div>
<script>
const ts = document.getElementById('ts');
const iso = document.getElementById('iso');
const human = document.getElementById('human');
const favsEl = document.getElementById('favs');
const KEY = 'epochkit-favs';
function loadFavs() {
try { return JSON.parse(localStorage.getItem(KEY) || '[]'); }
catch { return []; }
}
function saveFavs(arr) { localStorage.setItem(KEY, JSON.stringify(arr)); }
function parseTs(raw) {
const n = Number(String(raw).trim());
if (!Number.isFinite(n)) return null;
if (String(raw).length >= 13) return n;
return n * 1000;
}
function fromTs() {
const ms = parseTs(ts.value);
if (ms == null) return;
const d = new Date(ms);
iso.value = d.toISOString().slice(0, 19);
human.textContent = d.toLocaleString();
}
function fromIso() {
const d = new Date(iso.value);
if (isNaN(d)) return;
ts.value = Math.floor(d.getTime() / 1000);
human.textContent = d.toLocaleString();
}
ts.oninput = fromTs;
iso.oninput = fromIso;
document.getElementById('now').onclick = () => {
const d = new Date();
ts.value = Math.floor(d.getTime() / 1000);
fromTs();
};
document.getElementById('save').onclick = () => {
const label = prompt('Label for this timestamp?', iso.value);
if (!label) return;
const favs = loadFavs();
favs.push({ label, ts: ts.value });
saveFavs(favs.slice(-10));
renderFavs();
};
function renderFavs() {
favsEl.innerHTML = '';
loadFavs().forEach((f, i) => {
const b = document.createElement('button');
b.textContent = f.label;
b.onclick = () => { ts.value = f.ts; fromTs(); };
favsEl.appendChild(b);
});
}
renderFavs();
</script>
</body>
</html>
Milliseconds vs seconds
10-digit → multiply by 1000. 13-digit → use as-is. Stops the classic 1970 vs 2024 confusion.
localStorage quota
10 favorites max. Each is ~50 bytes — nowhere near 5MB limit.
Verify
Click Now → both fields populate
Save favorite → reload page → button restores timestamp
Enter 1714521600 → shows May 2024 UTC