The task is simple: show the current date and time on a page and update it every second. It is a familiar exercise when you are learning JavaScript, but there are a few things that are easy to get wrong.
The first version
function Clock() {
var today = new Date();
var date = today.getDate() + '-' + (today.getMonth() + 1) + '-' + today.getFullYear();
var time = today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
document.getElementById("current-time").innerHTML = date + ' ' + time;
}
setInterval(Clock, 1000);
And the HTML that places the clock wherever you want it:
<div id="current-time"></div>
A few things worth explaining:
new Date()with no argument returns the current moment according to the user’s machine.getMonth()returns a value from 0 to 11, so you have to add 1. This is the classic bug that makes September show up as August.setInterval(Clock, 1000)calls the function again every 1000 milliseconds.
Two bugs to fix
Bug one: no leading zeros. At 9:05:03 the code above prints 9:5:3 instead of 09:05:03. It looks wrong and the width of the text keeps jumping.
Bug two: the clock is blank for the first second. setInterval waits the full 1000ms before the first call, so the page sits empty for a second after it loads.
There is one more trap: if your HTML uses class="current-time" while the JavaScript calls getElementById, nothing is found and the browser throws Cannot set property 'innerHTML' of null. The selector has to match what you actually wrote in the HTML.
The finished version
function pad(n) {
return String(n).padStart(2, "0");
}
function updateClock() {
const el = document.getElementById("current-time");
if (!el) return;
const now = new Date();
const date = `${pad(now.getDate())}-${pad(now.getMonth() + 1)}-${now.getFullYear()}`;
const time = `${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
el.textContent = `${date} ${time}`;
}
updateClock(); // run immediately, do not wait a second
setInterval(updateClock, 1000);
The notable changes:
padStart(2, "0")adds a leading zero to make two digits.- Calling
updateClock()once beforesetIntervalso the clock appears straight away. - Using
textContentinstead ofinnerHTML. The content here is plain text, the browser does not need to parse HTML for it, sotextContentis both faster and removes any XSS risk if you later mix in data from elsewhere. - The
if (!el) return;guard so the script does not throw when the element is not there.
Using Intl for locale formatting
If you want locale-aware formatting rather than building the string by hand, the browser already has the tool:
const formatter = new Intl.DateTimeFormat("en-GB", {
dateStyle: "short",
timeStyle: "medium",
});
function updateClock() {
const el = document.getElementById("current-time");
if (el) el.textContent = formatter.format(new Date());
}
This handles date ordering, separators and time zones for you. Create the formatter once outside the function, because constructing it is relatively expensive and you do not want that happening every second.
To pin a specific time zone regardless of where the visitor is, add the option:
const formatter = new Intl.DateTimeFormat("en-GB", {
dateStyle: "short",
timeStyle: "medium",
timeZone: "Asia/Ho_Chi_Minh",
});
A note on accuracy
setInterval does not guarantee millisecond accuracy. When the tab is hidden, the browser throttles the callback to save battery, so the clock can drift. For a display clock that is fine, because each run reads new Date() fresh. But if you plan to use this for a countdown to a specific moment, do not accumulate one second at a time. Always compute the difference between the target time and Date.now().