Files
Seth a6b3f039d8 Initial commit — Seth Calendar & Decimal Time clock site
Pages: /, /simple, /decimal, /seth, /calendar, /astro, /convert, /timegov
Features: Seth Calendar (10×36 + holidays), decimal time, moon phases,
astronomy (sun/moon), bidirectional time converter, Seth date display,
leap day split cell in calendar grid.
2026-03-08 22:32:38 +00:00

150 lines
4.7 KiB
JavaScript

// Seth Time Converter
// Decimal time: 10 hours/day, 100 minutes/hour, 100 seconds/minute, 100 centiseconds/second
// Gregorian: 24 hours/day, 60 minutes/hour, 60 seconds/minute, 100 centiseconds/second
//
// Conversion: day fraction is the common unit
// Gregorian -> fraction: (H*3600 + M*60 + S + cs/100) / 86400
// Decimal -> fraction: (H*10000 + M*100 + S + cs/100) / 100000
const MS_PER_DAY = 86400000;
function gregToFraction(h, m, s, cs) {
return (h * 3600 + m * 60 + s + cs / 100) / 86400;
}
function decToFraction(h, m, s, cs) {
return (h * 10000 + m * 100 + s + cs / 100) / 100000;
}
function fractionToGreg(f) {
f = ((f % 1) + 1) % 1; // clamp 0..1
const totalCs = Math.round(f * 86400 * 100);
const cs = totalCs % 100;
const totalS = Math.floor(totalCs / 100);
const s = totalS % 60;
const totalM = Math.floor(totalS / 60);
const m = totalM % 60;
const h = Math.floor(totalM / 60) % 24;
return { h, m, s, cs };
}
function fractionToDec(f) {
f = ((f % 1) + 1) % 1;
const totalCs = Math.round(f * 100000 * 100);
const cs = totalCs % 100;
const totalS = Math.floor(totalCs / 100);
const s = totalS % 100;
const totalM = Math.floor(totalS / 100);
const m = totalM % 100;
const h = Math.floor(totalM / 100) % 10;
return { h, m, s, cs };
}
function pad(n, w) { return String(n).padStart(w, "0"); }
// DOM refs
const gH = document.getElementById("gH");
const gM = document.getElementById("gM");
const gS = document.getElementById("gS");
const gCs = document.getElementById("gCs");
const dH = document.getElementById("dH");
const dM = document.getElementById("dM");
const dS = document.getElementById("dS");
const dCs = document.getElementById("dCs");
const gregFrac = document.getElementById("gregFrac");
const decFrac = document.getElementById("decFrac");
let updating = false; // prevent feedback loops
function setGreg(h, m, s, cs) {
gH.value = pad(h, 2);
gM.value = pad(m, 2);
gS.value = pad(s, 2);
gCs.value = pad(cs, 2);
}
function setDec(h, m, s, cs) {
dH.value = h;
dM.value = pad(m, 2);
dS.value = pad(s, 2);
dCs.value = pad(cs, 2);
}
function updateFromGreg() {
if (updating) return;
updating = true;
const h = parseInt(gH.value) || 0;
const m = parseInt(gM.value) || 0;
const s = parseInt(gS.value) || 0;
const cs = parseInt(gCs.value) || 0;
const f = gregToFraction(h, m, s, cs);
const dec = fractionToDec(f);
setDec(dec.h, dec.m, dec.s, dec.cs);
gregFrac.textContent = `day fraction: ${f.toFixed(8)}`;
decFrac.textContent = `day fraction: ${f.toFixed(8)}`;
updating = false;
}
function updateFromDec() {
if (updating) return;
updating = true;
const h = parseInt(dH.value) || 0;
const m = parseInt(dM.value) || 0;
const s = parseInt(dS.value) || 0;
const cs = parseInt(dCs.value) || 0;
const f = decToFraction(h, m, s, cs);
const greg = fractionToGreg(f);
setGreg(greg.h, greg.m, greg.s, greg.cs);
gregFrac.textContent = `day fraction: ${f.toFixed(8)}`;
decFrac.textContent = `day fraction: ${f.toFixed(8)}`;
updating = false;
}
// Clamp inputs on change
function clampInput(el, min, max) {
el.addEventListener("change", () => {
let v = parseInt(el.value);
if (isNaN(v)) v = min;
el.value = Math.max(min, Math.min(max, v));
});
}
clampInput(gH, 0, 23); clampInput(gM, 0, 59);
clampInput(gS, 0, 59); clampInput(gCs, 0, 99);
clampInput(dH, 0, 9); clampInput(dM, 0, 99);
clampInput(dS, 0, 99); clampInput(dCs, 0, 99);
// Tab through fields on Enter or arrow keys within a panel
function setupNavigation(inputs) {
inputs.forEach((el, i) => {
el.addEventListener("keydown", e => {
if (e.key === "ArrowRight" || e.key === "Enter") {
e.preventDefault();
inputs[(i + 1) % inputs.length].focus();
inputs[(i + 1) % inputs.length].select();
}
if (e.key === "ArrowLeft") {
e.preventDefault();
inputs[(i - 1 + inputs.length) % inputs.length].focus();
inputs[(i - 1 + inputs.length) % inputs.length].select();
}
});
});
}
setupNavigation([gH, gM, gS, gCs]);
setupNavigation([dH, dM, dS, dCs]);
[gH, gM, gS, gCs].forEach(el => el.addEventListener("input", updateFromGreg));
[dH, dM, dS, dCs].forEach(el => el.addEventListener("input", updateFromDec));
// Now button — fill with current time and convert
document.getElementById("nowBtn").addEventListener("click", () => {
const now = new Date();
setGreg(now.getHours(), now.getMinutes(), now.getSeconds(), Math.floor(now.getMilliseconds() / 10));
updateFromGreg();
});
// Init with current time
const now = new Date();
setGreg(now.getHours(), now.getMinutes(), now.getSeconds(), Math.floor(now.getMilliseconds() / 10));
updateFromGreg();