const {
dtFrags,
dateAdd,
dateSubtract,
} = DateAddFactory();
const [until0, until1, toNwYr, fromNwYr] =
[...document.querySelectorAll(`#timedUntil, #timedUntil2, #timedUntilNewYear, #timedFromLastNewYear`)];
const thisYearsNewYear = new Date(Date.UTC(new Date().getFullYear(), 11, 31));
const timer = TimerFactory();
time(thisYearsNewYear, toNwYr, timer);
time(dateSubtract(dtFrags.year, 1, thisYearsNewYear), fromNwYr, timer);
time(dateAdd(dtFrags.seconds, 5), until0, timer);
time(dateAdd(dtFrags.seconds, 10), until1, timer, true);
function time(date, reportField, timer, continueAfterPassed = false) {
const isFuture = timer.toUTC(date) - timer.toUTC(new Date()) > 0;
const stopGo = {
stop: () => reportField.textContent = `${dateStr} passed`,
go: () => time(date, reportField, timer),
};
const dateStr = new Date(date).toUTCString();
const initStr = isFuture ?
`<div>Time until ${dateStr}</div>` :
`<div>From ${dateStr} until now lasted</div>`;
const passed = isFuture && !continueAfterPassed ? stopGo.stop : isFuture ? stopGo.go : null;
const writer = (difference, dtElements) => `
${initStr}${
dtElements.day(difference.days)} ${dtElements.hour(difference.hours)} ${
dtElements.minute(difference.minutes)} and ${dtElements.second(difference.seconds)}`;
return timer.createAndStartTimer(reportField, date, writer, passed);
}
function TimerFactory() {
const toUTC = someDate => Date.UTC(
someDate.getUTCFullYear(), someDate.getUTCMonth(), someDate.getUTCDate(),
someDate.getUTCHours(), someDate.getUTCMinutes(), someDate.getUTCSeconds());
const logTo = (field, args) => field.innerHTML = args;
const dtElements = dateTimeFragments(false);
const writerFactory = (field, writer, value) =>
diff => logTo(field, writer(diff, dtElements));
const createTimer = (field, dateValue, writer, callback) =>
counterFactory(dateValue, writerFactory(field, writer, dateValue), callback)
return {
createTimer,
createAndStartTimer: (...args) => createTimer.call(null, ...args)(),
toUTC,
};
function counterFactory(value, writer, callback) {
const showTime = () => {
const diffMS = value - new Date();
const reIterate = () => {
writer(dateDiffCalc(diffMS));
setTimeout(showTime, 1000);
};
const exitCounter = () => callback instanceof Function && callback();
return diffMS <= 0 && callback ? exitCounter() : reIterate();
};
return showTime;
}
function dateDiffCalc(milliseconds) {
let secs = Math.floor(Math.abs(milliseconds) / 1000);
let mins = Math.floor(secs / 60);
let hours = Math.floor(mins / 60);
let days = Math.floor(hours / 24);
const millisecs = Math.floor(Math.abs(milliseconds)) % 1000;
return {
days: days,
hours: hours % 24,
minutes: mins % 60,
seconds: secs % 60,
milliSeconds: millisecs,
};
}
function dateTimeFragments(doPad = true) {
const pad = (val, width = 2) => !doPad ? val : val < 1 ? val : String(val).padStart(width, "0");
const plural = (val, term) => `${term}${val !== 1 ? "s" : ""}`;
const checkZero = (val, term, comma) => val < 1 ?
"" : `<b>${pad(val)}</b> ${plural(val, term)}${comma ? ", " : ""}`;
return {
day: d => checkZero(d, "day", 1),
hour: h => checkZero(h, "hour", 1),
minute: m => `<b>${pad(m)}</b> ${plural(m, "minute")}`,
second: s => `<b>${pad(s)}</b> ${plural(s, "second")}`
};
}
}
function DateAddFactory() {
const dtFrags = {
year: {
set: "setFullYear",
get: "getFullYear"
},
month: {
set: "setMonth",
get: "getMonth"
},
date: {
set: "setDate",
get: "getDate"
},
hours: {
set: "setHours",
get: "getHours"
},
minutes: {
set: "setMinutes",
get: "getMinutes"
},
seconds: {
set: "setSeconds",
get: "getSeconds"
},
};
const dateAdd = (unit, value, date = new Date()) => {
date = new Date(date);
date[unit.set](date[unit.get]() + value);
return date;
};
return {
dtFrags,
dateAdd,
dateAddMulti: (values, date = new Date()) => {
while (values.length) {
const value = values.shift();
date = dateAdd(value.unit, value.val, date);
}
return date;
},
dateSubtract: (unit, value, date) => dateAdd(unit, -value, date),
};
}
<h3>
Count down or up to a given <i>UTC</i>-date
</h3>
<div id="timedUntil" data-timer></div>
<p>
<div>
<b>Next timer continues after the time has passed</b>
</div>
<div id="timedUntil2" data-timer></div>
</p>
<h3>
Time until next new year
</h3>
<div id="timedUntilNewYear" data-timer></div>
<h3>
The current year now lasts
</h3>
<div id="timedFromLastNewYear" data-timer></div>
body {
font: 16px/20px normal verdana, arial, helvetica;
margin: 1.5em;
}
[data-timer] {
margin-bottom: 0.7em;
}
[data-timer] div:first-child {
font-style: italic;
color: #AAA;
}
[data-timer] b {
color: green;
}
h3 {
margin-bottom: 0.3rem;
min-width: 200px;
text-decoration: underline;
}