JavaScript countdown with redirect


#1

Hi

I am trying to make a redirect timer that shows days , mins , hours and seconds anyone know how to do that?

The following code just displays “seconds” to screen.

<!-- Modify this according to your requirement -->
<h3>
  Redirecting to xxx after <span id="countdown">10</span> seconds
</h3>
<!-- JavaScript part -->
<script type="text/javascript">
    
    // Total seconds to wait
    var seconds = 10;
    
    function countdown() {
        seconds = seconds - 1;
        if (seconds < 0) {
            // Chnage your redirection link here
            window.location = "https://x.com";
        } else {
            // Update remaining seconds
            document.getElementById("countdown").innerHTML = seconds;
            // Count down using javascript
            window.setTimeout("countdown()", 1000);
        }
    }
    
    // Run countdown function
    countdown();
    
</script>

#2

Hello!

There is the modulo operator, which you can use to get the leftover of a division.

For example: after 61 seconds, the second unit shows 1 again, and the minute unit goes up.
You have to do that for every unit (seconds, minutes, hours, days, weeks or months and years)

This only works as long as you do not count in any leap seconds, because here “day” stands for 24 hours, not sometimes 24 hours and -/+ 1 second every 4 years. :wink:

You need either a fixed number in seconds or a new Date() from where you count down.

function getTimeLeft(to) {
    return ((to - new Date().getTime()) / 1000 | 0)
}

This is the main part of the script, that you have to calculate every single second:

let timeLeft = getTimeLeft(to)
const seconds = ((timeLeft % 60) + '').padStart(2, '0')
const minutes = (((timeLeft / 60) | 0) % 60 + '').padStart(2, '0')
const hours = ((timeLeft / 60 / 60 | 0) % 24 + '').padStart(2, '0')
const days = ((timeLeft / 60 / 60 / 24 | 0) + '')

When you have these informations, you can display them in terms of days/hours etc. your template:

let times = [
    {
        number : days,
        text : `Day${days!=1?'s':''}`
    },
    {
        number : hours,
        text : `Hour${hours!=1?'s':''}`
    },
    {
        number : minutes,
        text : `Minute${hours!=1?'s':''}`
    },
    {
        number : seconds,
        text : `Second${hours!=1?'s':''}`
    },
]
element.innerHTML = times
    .map(time => `${time.number} ${time.text}`)
    .join(' ')

This is what we can put within a setInterval function call:

We already need to stop the timer, once it reaches zero:

if (timeLeft < 0) {
    countdownOver(interval)
    return
}

function countdownOver(interval, element) {
    clearInterval(interval)
	element.innerHTML = 'countdown over'
}

All put together, the countdown function with interval and clearinterval, you get the following:

function getTimeLeft(to) {
    return ((to - new Date().getTime()) / 1000 | 0)
}

function countdownOver(interval, element) {
    clearInterval(interval)
	element.innerHTML = 'countdown over'
}

function countdown(element, to) {
    let timeLeft = getTimeLeft(to)
    if (timeLeft >= 0) {
        interval = setInterval(()=>{
            let timeLeft = getTimeLeft(to)
            if (timeLeft < 0) {
                countdownOver(interval, element)
                return
            }
            const seconds = ((timeLeft % 60) + '').padStart(2, '0')
            const minutes = (((timeLeft / 60) | 0) % 60 + '').padStart(2, '0')
            const hours = ((timeLeft / 60 / 60 | 0) % 24 + '').padStart(2, '0')
            const days = ((timeLeft / 60 / 60 / 24 | 0) + '')
            let times = [
                {
                    number : days,
                    text : `Day${days!=1?'s':''}`
                },
                {
                    number : hours,
                    text : `Hour${hours!=1?'s':''}`
                },
                {
                    number : minutes,
                    text : `Minute${hours!=1?'s':''}`
                },
                {
                    number : seconds,
                    text : `Second${hours!=1?'s':''}`
                },
            ]
            element.innerHTML = times
                .map(time => `${time.number} ${time.text}`)
                .join(' ')
        }, 1000)
    }
}

So now we need to call that function for the DOM element that you want to count down with.
To make it work for more than one element (#countdown) we use a component-based approach:

// initialize component
document.querySelectorAll('.js-countdown').forEach(element => {
	let countTo = new Date(element.dataset.date).getTime()
	countdown(element, countTo)
})

I created a working codepen here:

Good luck :slight_smile: