Explanation
Problem 1: It refreshes with the browser refresh.
Cause: Because you hardcoded the seconds and minutes (var seconds = 5
, var minutes = 1
), every user that visits the page will see the timer counting down from the exact same value being "1 minute and 5 seconds remaining" again and again.
Solution: Instead of hardcoding the start value of the countdown, hardcode the deadline. So instead of saying to each visitor of your page "Start counting down from 1 min and 5 sec to 0!", you have to say something like "Count down from whatever time it is now to midnight!". This way, the countdown will always be synced across different users of your website (assuming that their computer clock is set correctly).
Problem 2: It doesn't have hours.
Cause: Your code has only variables to keep track of seconds and minutes, there is no code written to keep track of the hours.
Solution: Like proposed in the solution for problem 1: don't keep track of the hours/minutes/seconds remaining, but only keep track of the deadline and then calculate hours/minutes/seconds remaining based on the current client time.
Problem 3: It does not auto-repeat when the timer reaches zero.
Cause: The nested if
s (that check seconds == 0
and m == 0
) in your code explicitly state to display the text "countdown's over!" when the countdown is over.
Solution: Keep a conditional that checks when the countdown is over but instead of displaying "countdown's over!", reset the deadline to a next deadline.
Problem 4: For every user time remaining varies.
Cause: See Problem 1
Solution: See Problem 1
Sample code
here is a piece of code that integrates the solutions mentioned above:
const span = document.getElementById('countdown')
const deadline = new Date
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
function displayRemainingTime() {
if (deadline < new Date) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - new Date
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
const string = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
window.setInterval(displayRemainingTime, 1000)
displayRemainingTime()
<h3>
<span id="countdown"></span>
</h3>
Edit: make sure the client time is correct
If you don't trust your clients for having their time set up correctly. You can also send a correct timestamp from the server that serves your page. Since I don't know what kind of server you are using I can't give an example for your server code. But basically you need to replace the code (from the following example) after const trustedTimestamp =
(being (new Date).getTime()
) with a correct timestamp that you generate on the server. For the correct formatting of this timestamp refer to Date.prototype.getTime()
const span = document.getElementById('countdown')
const trustedTimestamp = (new Date).getTime()
let timeDrift = trustedTimestamp - (new Date)
const now = () => new Date(timeDrift + (new Date).getTime())
const deadline = now()
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
function displayRemainingTime() {
if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - now()
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
window.setInterval(displayRemainingTime, 1000)
displayRemainingTime()
<h3>
<span id="countdown"></span>
</h3>
Time from google server
To create a working example I added this experiment where I get the correct time from a Google page. Do not use this code on your website because it is not guaranteed that google will keep hosting this web-page forever.
const span = document.getElementById('countdown')
const trustedTimestamp = (new Date).getTime()
let timeDrift = 0
const now = () => new Date(timeDrift + (new Date).getTime())
const deadline = now()
deadline.setHours(0)
deadline.setMinutes(0)
deadline.setSeconds(0)
window.setInterval(displayRemainingTime, 1000)
window.setInterval(syncClock, 3000)
displayRemainingTime()
syncClock()
function displayRemainingTime() {
if (deadline < now()) deadline.setDate(deadline.getDate() + 1)
const remainingTime = deadline - now()
const extract = (maximum, factor) => Math.floor((remainingTime % maximum) / factor)
const seconds = extract( 60000, 1000 )
const minutes = extract( 3600000, 60000 )
const hours = extract(86400000, 3600000)
span.innerText = `${hours} hours ${minutes} minutes ${seconds} seconds remaining`
}
function syncClock() {
const xmlhttp = new XMLHttpRequest();
xmlhttp.open("HEAD", "http://www.googleapis.com",true);
xmlhttp.onreadystatechange = function() {
const referenceTime = new Date
if (xmlhttp.readyState==4) {
const correctTime = new Date(xmlhttp.getResponseHeader("Date"))
timeDrift = correctTime - referenceTime
}
}
xmlhttp.send(null);
}
<h3>
<span id="countdown"></span>
</h3>