XKCD 6/6 Time
by Ondřej Žára
HTML
<span id="clock"></span>
<ul>
<li>Browser requirements: async/await, allowed geolocation</li>
<li>Implements <a href="https://xkcd.com/2050/">https://xkcd.com/2050/</a></li>
<li>Uses <a href="https://sunrise-sunset.org/api">https://sunrise-sunset.org/api</a></li>
<li>Created by <a href="https://ondras.zarovi.cz/">Ondřej Žára</a></li>
</ul>
JavaScript
let lat = 0, lon = 0;
let before = null, after = null, h0 = null;
const S = 1000;
const M = 60*S;
const H = 60*M;
async function getSun(date = "today") {
let response = await fetch(`https://api.sunrise-sunset.org/json?lat=${lat}&lng=${lng}&formatted=0&date=${date}`);
let data = await response.json();
return {
sunrise: new Date(data.results.sunrise).getTime(),
sunset: new Date(data.results.sunset).getTime()
}
}
async function onPosition(position) {
lat = position.coords.latitude;
lng = position.coords.longitude;
update();
}
function onError(e) {
alert(e.message);
}
function show(h, m, s) {
let node = document.querySelector("#clock");
let h_ = (h+h0) % 24;
let m_ = m.toString().padStart(2, "0");
let s_ = s.toString().padStart(2, "0");
node.textContent = `${h_}:${m_}:${s_}`;
}
async function updateBeforeAfter() {
// fixme before sunrise, after sunset
let sun = await getSun();
let now = Date.now();
if (now < sun.sunrise) {
after = sun.sunrise;
sun = await getSun("yesterday");
before = sun.sunset;
h0 = 18;
} else if (now > sun.sunset) {
before = sun.sunset
sun = await getSun("tomorrow");
after = sun.sunrise;
h0 = 18;
} else {
before = sun.sunrise;
after = sun.sunset;
h0 = 6;
}
update();
}
function update() {
let now = Date.now();
if (before === null || now < before || now > after) {
return updateBeforeAfter();
}
const totalMsReal = 12 * H;
const totalMsXkcd = after-before;
let elapsedMsReal = (now - before);
let elapsedMsXkcd = elapsedMsReal * (totalMsXkcd / totalMsReal);
let ms = elapsedMsXkcd;
let h = Math.floor(ms / H);
ms = ms % H;
let m = Math.floor(ms / M);
ms = ms % M;
let s = Math.round(ms / S);
show(h, m, s);
setTimeout(update, 500);
}
navigator.geolocation.getCurrentPosition(onPosition, onError);
/* date mock
Date.now = () => {
return new Date().getTime() - 12*H;
}
*/