DEV Community

loading...
Cover image for Simple Countdown Timer using JavaScript

Simple Countdown Timer using JavaScript

Foolish Developer
Updated on ・4 min read

JavaScript countdown timers are used on a variety of e-commerce and under-construction websites to keep users up to date. We see on different types of e-commerce websites that a kind of countdown starts some time before the arrival of any product or offer.
In this article I have created a countdown timer using simple JavaScript code and shared it with you.

You can watch its live demo to know how it works. Creating such a project is much easier if you know how to create a digital clock. Here you can schedule a specific day or time in advance. Then, with the help of JavaScript code, subtracting the current time from that time, the subtraction is reduced every second.

As you can see in the picture above I have used the web page background # 90cbf3 here. The page contains four small boxes for days, hours, minutes and seconds, respectively. First of all you have to create an HTML and CSS file.

Step 1: Basic structure of Countdown Timer

Only one line of HTML programming code has been used. Then I designed the webpage using the css code below. With background # 90cbf3 you can use any other color you want.

<div id="timer"></div>
Enter fullscreen mode Exit fullscreen mode
body {
    text-align: center;
    padding: 100px 60px;
    background: #90cbf3;
    font-family: sans-serif;
    font-weight: lighter;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Step 2: Activate it using JavaScript code

Now I have implemented this countdown timer with the help of JavaScript. First of all, we have set a specific date with the help of Date.parse. that is, you have to determine for what time you want to run the countdown.

future = Date.parse("jun 12, 2022 01:30:00");
Enter fullscreen mode Exit fullscreen mode

Then using the new Date () method I have taken the current time from the device. In this case, let me tell you, the time to use here is not the time of any server. It is only the local time of your device.

Then I subtract the current time from the pre-determined time and store it in the diff (constant). As a result, I have got a total of how much time to countdown.

 now = new Date();
 diff = future - now;
Enter fullscreen mode Exit fullscreen mode

Now I have converted the total time of countdown to days, hours, minutes and seconds using JavaScript's Math.floor.

➤ We know that one second is equal to 1000 milliseconds, so we have divided the whole countdown time (diff) by 1000.
➤ Right now one minute is equal to 60 seconds so in this case we have divided by 1000 * 60.
➤ Since one hour is equal to 60 minutes, in this case we have divided by 1000 * 60 * 60.
➤ One day is equal to 24 hours so in this case it is divided by 1000 * 60 * 60 * 24.

 days = Math.floor(diff / (1000 * 60 * 60 * 24));
 hours = Math.floor(diff / (1000 * 60 * 60));
 mins = Math.floor(diff / (1000 * 60));
 secs = Math.floor(diff / 1000);
Enter fullscreen mode Exit fullscreen mode
 d = days;
 h = hours - days * 24;
 m = mins - hours * 60;
 s = secs - mins * 60;
Enter fullscreen mode Exit fullscreen mode

Above we have done all the work of calculation, now we will arrange it neatly in the web page. For this I have used innerhtml and in it I have beautifully arranged how it can be seen in the webpage. Here I have added text like day, hours, minutes, seconds etc. using span respectively.

 document.getElementById("timer")
  .innerHTML =
  '<div>' + d + '<span>Days</span></div>' +
  '<div>' + h + '<span>Hours</span></div>' +
  '<div>' + m + '<span>Minutes</span></div>' +
  '<div>' + s + '<span>Seconds</span></div>';
Enter fullscreen mode Exit fullscreen mode

Lastly, I have instructed to update this calculation every 1000 milliseconds using setInterval. Since the countdown time is intermittent every second, this system needs to be updated every second.

setInterval('updateTimer()', 1000);
Enter fullscreen mode Exit fullscreen mode

Alt Text

Final JavaScript code

function updateTimer() {
    future = Date.parse("jun 12, 2022 01:30:00");
 now = new Date();
 diff = future - now;

 days = Math.floor(diff / (1000 * 60 * 60 * 24));
 hours = Math.floor(diff / (1000 * 60 * 60));
 mins = Math.floor(diff / (1000 * 60));
 secs = Math.floor(diff / 1000);

 d = days;
 h = hours - days * 24;
 m = mins - hours * 60;
 s = secs - mins * 60;

 document.getElementById("timer")
  .innerHTML =
  '<div>' + d + '<span>Days</span></div>' +
  '<div>' + h + '<span>Hours</span></div>' +
  '<div>' + m + '<span>Minutes</span></div>' +
  '<div>' + s + '<span>Seconds</span></div>';
}
setInterval('updateTimer()', 1000);
Enter fullscreen mode Exit fullscreen mode

Step 3: Give the times the size of a box

Now I have designed it using some basic css code and arranged it beautifully in web pages. As you can see in the picture above there is a small box to hold each time. I created that box using the code below. In this case I have used the background-color of the box # 020b43.

#timer {
    font-size: 3em;
    font-weight: 100;
    color: white;
    padding: 20px;
    width: 700px;
    color: white;

}

#timer div {
    display: inline-block;
    min-width: 90px;
    padding: 15px;
    background: #020b43;
    border-radius: 10px;
    border: 2px solid #030d52;
    margin: 15px;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Step 4: Design the text

Now at the end of it all I will design the text that I added using the span in the JavaScript code. I have used the following css to determine the size, color, etc. of those texts.

#timer div span {
    color: #ffffff;
    display: block;
    margin-top: 15px;
    font-size: .35em;
    font-weight: 400;
}
Enter fullscreen mode Exit fullscreen mode

Alt Text

Hopefully from this tutorial you have learned how to build a countdown timer using JavaScript code. Please let me know in the comments how you like this tutorial. If I have done anything wrong, please let me know in the comments.

You can visit my blog for more tutorials like this.
https://www.foolishdeveloper.com/

Discussion (8)

Collapse
lukeshiru profile image
LUKESHIRU

A few suggestions for the JS portion:

  • Use const/let for variables. Putting just the name declares them as globals, and you don't want that.
  • Ideally you should have the part that calculates the difference, and the part that sets the content of the HTML element separated.
  • Use less magic numbers.
  • The first argument of a setInterval or a setTimeout should be a function, not a string (it isn't recommended for the same reasons eval is not recommended).

Here it is with those fixes and some more:

// No magic numbers...

const SECOND = 1000;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;

/**
 * Calculates the difference between two timestamps, returns a quadruple with
 * the difference in days, hours, minutes and seconds.
 *
 * @param {number} future
 */
const timestampDiff =
    future =>
    /** @param {number} past */
    past =>
        [DAY, HOUR, MINUTE, SECOND].map((time, index, times) => {
            const diff = future - past;
            const previousTime = times[index - 1];

            return (
                Math.floor(diff / time) -
                (Math.floor(diff / previousTime) * (previousTime / time) || 0)
            );
        });

/**
 * Start timer and set the content of the element.
 *
 * @param {string} date
 */
const timer =
    date =>
    /** @param {HTMLElement} target */
    target => {
        const diff = timestampDiff(Date.parse(date));

        return setInterval(() => {
            const [days, hours, minutes, seconds] = diff(Date.now());

            // Ideally we should have targets for every element
            // to avoid updating the entire innerHTML of the container with
            // every tick.
            target.innerHTML = `
                <div>${days}<span>Days</span></div>
                <div>${hours}<span>Hours</span></div>
                <div>${minutes}<span>Minutes</span></div>
                <div>${seconds}<span>Seconds</span></div>
            `;
        }, SECOND);
    };

// We finally run it (and we save the interval return value if we wan to stop it later)
const interval = timer("jun 12, 2022 01:30:00")(document.querySelector("#timer"));
Enter fullscreen mode Exit fullscreen mode
Collapse
anubarak profile image
Robin Schambach • Edited

What's the purpose of returning a function by your timer function instead of using 2 arguments?

As for your other changes I wanted to explain the very same things and couldn't agree more. However in my opinion your syntax to start the timer kinda looks ugla to be to be honest. The same goes for timestampDiff seems only harder to read.

Collapse
lukeshiru profile image
LUKESHIRU • Edited
  • Functions returning functions is a technique called currying. The purpose is to reuse timestampDiff with the same future date but different starting dates if you want:
// Returns a function
const diff = timestampDiff(Date.parse("Aug 1, 2022, 10:00:00"));

// That we can reuse...
const diffWithNow = diff(DateNow());
const diffWithYesterday = diff(Date.parse("July 30, 2022, 10:00:00"));
Enter fullscreen mode Exit fullscreen mode

The same happens with timer, you can start the timer with any date compared to now, and then set as many elements as you want to have the same timer on it, not just one :D

  • The syntax of timestampDiff is doing the same thing, but with a map instead of multiple functions. My first approach was pretty similar to what the author has:
const diff = future - now;

// The same floor 4 times
const totalDays = Math.floor(diff / DAY);
const totalHours = Math.floor(diff / HOUR);
const totalMinutes = Math.floor(diff / MINUTE);
const totalSeconds = Math.floor(diff / SECOND);

// The same logic 4 times again
const days = totalDays;
const hours = totalHours - totalDays * 24;
const minutes = totalMinutes - totalHours * 60;
const seconds = totalSeconds - totalMinutes * 60;

// And we return a quadruple (array with 4 values)
return [days, hours, minutes, seconds];
Enter fullscreen mode Exit fullscreen mode

As you can see, we have a pattern that keeps on repeating. My approach takes the original 4 values and maps them into the quadruple. Here is with comments to make it easier to understand:

// `time` will have the value of every "time unit"
// `index` is self explanatory
// `times` is the original quadruple.
[DAY, HOUR, MINUTE, SECOND].map((time, index, times) => {
    // We save the diff between future and past to reuse it
    const diff = future - past;
    // We also save the previous time unit (if we are in HOUR, then is DAY
    // if we are in DAY then is `undefined`
    const previousTime = times[index - 1];

    // This is the logic that was repeated 4 times previously
    return (
        Math.floor(diff / time) -
        // This will return `NaN` for DAY, so we turn it into a `0`
        (Math.floor(diff / previousTime) * (previousTime / time) || 0)
    );
})
Enter fullscreen mode Exit fullscreen mode

You can now add a milliseconds unit, for example, and have a more detailed countdown if you want, by just changing the initial tuple.

Thread Thread
anubarak profile image
Robin Schambach

I see thank you for your detailed explanation. Maybe I should have asked my question in a different way 😅

I know that pattern but I don't like it that much.
The question should be more like "I don't get the advantage over calling one single method with multiple arguments" as it requires less memory in larger scales. When you have a loop or use this pattern in a recursion I think it's not worth it (of course in this case without something else it is trivial). If I really need such a case I prefer classes over that pattern as it's easier to read at the very first glance (when you have to dig through several hundred lines of code within a few seconds)

I guess it all depends on person preferences and what people are used too. Then again thanks for your code I bet it helps many people.

Thread Thread
lukeshiru profile image
LUKESHIRU

Is definitely a preference thing. I write mainly unary functions and default to currying almost always. Not to mention that I don't like classes and I luckily haven't had the need to use them in a very long time :D

Collapse
chrmc7 profile image
Chris ☕️

Looks good to me! Thank you for the tutorial 👍

Collapse
code_mystery profile image
Foolish Developer Author

Welcome 😀

Collapse
cyril174 profile image
Cyril Kariyawasam

Thanks. Very helpful.