Make a function setInterval/recursive - javascript

I've got a function here that outputs seconds as days, minutes, and seconds, and I'd like it run once a second, and add one to the delta - giving a semi accurate difference between two dates.
$(document).ready(function() {
if ($("#time").length) {
var delta = document.getElementById('time').innerHTML;
function timer(delta) {
setInterval(function() {
// calculate (and subtract) whole days
var days = Math.floor(delta / 86400);
delta -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(delta / 3600) % 24;
delta -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(delta / 60) % 60;
delta -= minutes * 60;
// what's left is seconds
var seconds = delta % 60;
// console.log(minutes);
console.log(days + " " + hours + " " + minutes + " " + seconds)
timer(delta + 1)
}, 1000);
}
}
});
What do I need to change to achieve this? I have some familiarity with recursion - but not a lot, in all honesty.

Change 'setInterval' to 'setTimeout'.
setInterval according to MDN:
Repeatedly calls a function or executes a code snippet, with a fixed
time delay between each call. Returns an intervalID.
Which means that it will run the once per 1000ms, and call the timer() function that will spawn another setInterval. Now you'll have to 2 setInterval running, 4 after 1000ms, etc...
setTimeout on the other hand expires after it invokes the callback. The callback will execute, and start a new timer, and the cycle will continue.
var time = document.getElementById('time');
function timer(delta) {
setTimeout(function() {
// calculate (and subtract) whole days
var days = Math.floor(delta / 86400);
delta -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(delta / 3600) % 24;
delta -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(delta / 60) % 60;
delta -= minutes * 60;
// what's left is seconds
var seconds = delta % 60;
time.innerHTML = (days + " " + hours + " " + minutes + " " + seconds);
timer(delta + 1)
}, 1000);
}
timer(0);
<div id="time"></div>

You can continue to use setInterval() if you update the outer variable delta within your timer() function
var delta = document.getElementById('time').innerHTML;
function timer() {
// calculate (and subtract) whole days
var days = Math.floor(delta / 86400);
delta -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(delta / 3600) % 24;
delta -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(delta / 60) % 60;
delta -= minutes * 60;
// what's left is seconds
var seconds = delta % 60;
// console.log(minutes);
document.getElementById('result').innerHTML = days + " " + hours + " " + minutes + " " + seconds;
delta++;
}
setInterval(timer, 1000);
<div id="time">0</div>
<div id="result"></div>

Here's how I would write it out :
$(document).ready(function() {
function Timer(delta) {
// Local variables
var delta, intervalId;
this.start = function(initialDelta) {
if (!intervalId) {
delta = initialDelta;
intervalId = window.setInterval(function() {
// calculate (and subtract) whole days
var days = Math.floor(delta / 86400);
delta -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(delta / 3600) % 24;
delta -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(delta / 60) % 60;
delta -= minutes * 60;
// what's left is seconds
var seconds = delta % 60;
// console.log(minutes);
console.log(days + " " + hours + " " + minutes + " " + seconds)
delta++;
})
}
}
this.stop = function() {
if (intervalId) {
window.clearInterval(intervalId);
}
}
}
if ($("#time").length) {
var timer = new Timer();
var delta = parseInt(document.getElementById('time').innerHTML);
timer.start(delta);
window.setTimeout(function() { timer.stop(); }, 5000);
}
});
Quick explanation : by using a constructor function Timer, you can isolate delta to each instance of Timer (like a private variable of a class in Java). By doing this, you avoid having to use recursion and your initial method using setInterval works perfectly well for this purpose, because every time the function is called, it can access and modify its own local delta.
This would allow you to start multiple timers, start them with different delta values, etc..

Related

Countdown Timer every 15-Minutes in the hour

I have a webinar that runs every 15 minutes of every hour of the day (EG: 11:00, 11:15, 11:30 & 11:45).
I'd like a countdown timer that shows the remaining minutes until the next start time and all I can find from days of searches and trying to figure this out myself is an hourly countdown.
My question is, how do I update this code for be every 15 minutes not every 60.
<script>
/* Return minutes and seconds to next hour
** #returns {Object} minutes: minutes remaining
** seconds: seconds remaining
*/
function getTimeRemaining() {
var t = Date.now();
var seconds = (60 - Math.floor(t % 6e4 / 1e3)) % 60;
var minutes = 60 - Math.ceil(t % 3.6e6 / 6e4) + (seconds? 0:1);
return {
'minutes': ('0' + minutes).slice(-2),
'seconds': ('0' + seconds).slice(-2) };
}
// Simple show remaining function
function showRemaining() {
var r = getTimeRemaining();
document.getElementById('clock').textContent = (r.minutes + ':' + ('0' + r.seconds).slice(-2));
// Run again just after next full second
setTimeout(showRemaining, 1020 - (Date.now() % 1000));
}
showRemaining();
</script>
That solution seems overly complicated and you should be definitely using setInterval for a task where you have to update something every x seconds, recursively calling setTimeout is a bad idea. Here is a solution that is much more understandable:
const runEvery = 15 * 60; // 15 minutes in seconds
const showRemaining = () => {
// get current time in seconds and find when the next run starts in seconds
const seconds = Math.round(Date.now() / 1000);
const nextRun = runEvery * Math.ceil(seconds / runEvery);
const timeLeft = nextRun - seconds;
const minutesLeft = Math.floor(timeLeft / 60);
const secondsLeft = timeLeft % 60;
document.getElementById('clock').textContent = minutesLeft + ':' + ('0' + secondsLeft).slice(-2);
}
showRemaining();
setInterval(showRemaining, 1000);
<div id="clock"></div>

How can I organize my code more in order to prevent the undesired behavior?

As of now, I've written a script for a timer to countdown to a specific day. The problem is that the moment you refresh the browser, it takes 1 second for it to appear as opposed to it appearing instantly.
I actually did figure out a way to make it appear instantly but I had to repeat the block of code with countDownDate, now, timeDifference, oneDay, days, hours, minutes, seconds and document.getElementById("timer").innerHTML = ...; by placing it directly on top of timer() which's totally inefficient.
In my attempt below, the countdown appears about one second upon the browser refreshing but I want it to appear instantly. My goal here is to create reusable code.
What am I doing wrong and how can I fix it?
Here's the html:
<h1 id="timer"></h1>
Here's the js:
function conversion() {
var countDownDate = new Date("June 1, 2019 24:00:00");
var now = new Date().getTime();
var timeDifference = countDownDate - now;
var oneDay = 1000 * 60 * 60 * 24;
var days = Math.floor(timeDifference / (oneDay));
var hours = Math.floor((timeDifference % (oneDay)) / (1000 * 60 * 60));
var minutes = Math.floor((timeDifference % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((timeDifference % (1000 * 60)) / 1000);
document.getElementById("timer").innerHTML = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
}
function timerCountdown() {
var timer = setInterval(function() {
conversion();
if(timeDifference < 0) {
clearInterval(timer);
document.getElementById("timer").innerHTML = "Timer's over.";
}
}, 1000);
}
timerCountdown();
Put the setInterval callback into a variable, and both call setInterval with that function and call it immediately on pageload:
function timerCountdown() {
var timer = setInterval(intervalCb, 1000);
function intervalCb() {
conversion();
if(timeDifference < 0) {
clearInterval(timer);
document.getElementById("timer").innerHTML = "Timer's over.";
}
}
intervalCb();
}
timerCountdown();
Just call conversion() immeadiately.

Make a JS countdown starts again

I alreay have some code for a countdown, but would like to make it pause for some hours when at 0 (with a text displayed), and then starts again for 14 days.
<script type="text/JavaScript">
var Display=document.getElementById("Counter");
function Countdown() {
var date1 = new Date();
var date2 = new Date ("Oct 20 20:00:00 2017");
var sec = (date2 - date1) / 1000;
var n = 24 * 3600;
if (sec > 0) {
j = Math.floor (sec / n);
h = Math.floor ((sec - (d * n)) / 3600);
mn = Math.floor ((sec - ((d * n + h * 3600))) / 60);
sec = Math.floor (sec - ((d * n + h * 3600 + mn * 60)));
Affiche.innerHTML = "Next game in : " + d +" d "+ h +" h "+ mn +" min "+ sec + " s ";
window.status = "Remaining time : " + d +" d "+ h +" h "+ mn +" min "+ sec + " s ";
}
tCountdown=setTimeout ("Countdown();", 1000);
}
Countdown();
</script>
So to sum up:
1. The countdown reach 0
2. It blocks for 4 hours and display a text ("We are currently playing")
3. It starts again for around 14 days.
I am thinking of something like this to start again the countdown:
var dateX = var date2 + (a length of time around 14 days)
Am I right?
Can I do this only with Javascript?
I broke it up into a bunch of functions so you can reason about it. If you want to test it, you can set the initial seconds in the sec variable to something small, like 10, and then you can also set the second argument in setTimeout to something small, like 10.
<div id="counter"></div>
<script>
// initialize
var first_target_date = new Date ("Oct 20 20:00:00 2017");
var sec = calcSecDiff(new Date(), first_target_date);
var counter = document.getElementById("counter");
var timeout; // we will update this global variable when we want to stop the whole thing
// start the countdown
countdown();
// do it again every second
var interval = setInterval(function(){
countdown();
}, 1000);
function countdown() {
counter.innerHTML = parseTime(sec);
// decrement the second
sec--;
// if we get to 0
if (sec < 0) {
clearInterval(interval);
counter.innerHTML = "We are currently playing";
if (timeout) return; // it's over
var timeout = setTimeout(function(){
sec = daysToSec(14); // reset the seconds to 14 days away
var interval = setInterval(function(){
countdown();
}, 1000);
}, hrsToMs(4)); // wait four hours before counting down again
};
}
// returns days, hours, minutes, and seconds from seconds
// see https://stackoverflow.com/questions/13903897/javascript-return-number-of-days-hours-minutes-seconds-between-two-dates
function parseTime(sec){
// calculate (and subtract) whole days
var days = Math.floor(sec / 86400);
sec -= days * 86400;
// calculate (and subtract) whole hours
var hours = Math.floor(sec / 3600) % 24;
sec -= hours * 3600;
// calculate (and subtract) whole minutes
var minutes = Math.floor(sec / 60) % 60;
sec -= minutes * 60;
// what's left is seconds
var seconds = sec % 60;
return days + " days, " + hours + " hours, " + minutes + " minutes, " + seconds + " seconds";
}
// calculates the difference between two dates in seconds
function calcSecDiff(date1, date2){
return Math.round((date2 - date1) / 1000);
}
// converts hours to milliseconds
function hrsToMs(hrs){
return hrs * 60 * 60 * 1000;
}
// converts days to seconds
function daysToSec(days){
return days * 24 * 60 * 60;
}
</script>

Countdown timer to a date set from admin panel

I am trying to make a countdown timer that will countdown to a certain date and time.
I would like to be able to set the date and time from a 'admin panel' by typing in the date and time(ex 2014-01-25, 15:00) in a textbox or something similar.
As you might've figured, I'm not the best at PHP or JavaScript and I'm in need of directions as of how I would do this.
Any help is appreciated as I haven't made any progress in the last 2 hours I've tried doing this.
To do this with no frameworks like JQuery, you can do the following:
var MINUTE_IN_MILLISECONDS = 60 * 1000;
var HOUR_IN_MILLISECONDS = 60 * MINUTE_IN_MILLISECONDS;
var YEAR_IN_MILLISECONDS = 24 * HOUR_IN_MILLISECONDS;
var targetDate = new Date('2014-01-25 15:00');
var countdownInterval;
function countdown(){
var currentDate = new Date();
var difference = targetDate.getTime() - currentDate.getTime();
//Countdown has expired, cancel interval and do other tasks here
if(difference <= 0)
{
difference = 0;
clearInterval(countdownInterval);
//Update button here
}
var days = Math.floor(difference / YEAR_IN_MILLISECONDS);
difference -= days * YEAR_IN_MILLISECONDS;
var hours = Math.floor(difference / HOUR_IN_MILLISECONDS);
difference -= hours * HOUR_IN_MILLISECONDS;
var minutes = Math.floor(difference / MINUTE_IN_MILLISECONDS);
difference -= minutes * MINUTE_IN_MILLISECONDS;
var seconds = Math.floor(difference / 1000);
console.log(days + ":" + hours + ":" + minutes + ":" + seconds);
}
countdownInterval = setInterval(countdown, 1000);
Here's the Fiddle
Full demonstration: http://jsfiddle.net/DerekL/T48SL/
<form>
<input type="date" required><input type="time" required>
<input type="submit">
</form>
<span></span>
$("form").on("submit", function (e) {
e.preventDefault();
var date = $("input[type=date]").val(),
time = $("input[type=time]").val(),
targetTime = new Date(date + " " + time),
interval = setInterval(function () {
$("span").html(
(((+startingTime - Date.now()) / 1000)|0) + " seconds left until " + startingTime.toString() + "."
);
}, 500);
});
It is fairly easy to format the time instead of just seconds with Algebra:
//yourTime is in seconds
(yourTime) % 60 //seconds
(yourTime / 60 |0) % 60 //minutes
(yourTime / 3600 |0) % 24 //hours
(yourTime / 86400 |0) //days
/*
* Explanation:
* % is mod, it finds the remainder of two numbers.
* |0 is binary OR, it rounds down a floating number.
*
*/
With this technique, you do not need to do a bunch of subtraction and create a lot of junk variables in the process.

JavaScript count down, add hours & minutes

So, I have the below (seconds countdown) in good order. But! I am trying to add hours & minutes as apart of the count down as well. Ideally keeping the same structure, and just using pure JS. I would like the output to be:
There is X hours, X minutes, and X seconds remaining on this Sale!
var count=30;
var counter=setInterval(timer, 1000); //1000 will run it every 1 second
function timer()
{
count=count-1;
if (count <= 0)
{
clearInterval(counter);
return;
}
document.getElementById("timer").innerHTML=count + " secs"; // watch for spelling
}
If the solution has to be a rewrite with jQuery or another library; that's fine. Just not preferable.
Cheers and Salutations for any help.
Something like this:
var count = 30;
var counter = setInterval(timer, 1000); //1000 will run it every 1 second
function timer() {
count = count - 1;
if (count == -1) {
clearInterval(counter);
return;
}
var seconds = count % 60;
var minutes = Math.floor(count / 60);
var hours = Math.floor(minutes / 60);
minutes %= 60;
hours %= 60;
document.getElementById("timer").innerHTML = hours + "hours " + minutes + "minutes and" + seconds + " seconds left on this Sale!"; // watch for spelling
}
var totalSeconds = 3723; // lets say we have 3723 seconds on the countdown
// that's 1 hour, 2 minutes and 3 seconds.
var hours = Math.floor(totalSeconds / 3600 );
var minutes = Math.floor(totalSeconds % 3600 / 60);
var seconds = totalSeconds % 60;
var result = [hours, minutes, seconds].join(':');
console.log(result);
// 1:2:3
hours is seconds divided by the number of seconds in hour (3600) rounded down
minutes is the remainder of the above division, divided by the number of seconds in a minute (60), rounded down.
seconds is the remainder of total seconds divided by seconds in a minute.
Each calculation after hour has to use a modulus calculation to get the remainder, because you don't care about total time at that step, just progress to the next tick.
I would use a similar method to the others, but I wouldn't rely on setInterval / setTimeout as a timer, especially if users might be looking at the page for some time, as it tends to be inaccurate.
var endTime = new Date(2013, 10, 31).getTime() / 1000;
function setClock() {
var elapsed = new Date().getTime() / 1000;
var totalSec = endTime - elapsed;
var d = parseInt( totalSec / 86400 );
var h = parseInt( totalSec / 3600 ) % 24;
var m = parseInt( totalSec / 60 ) % 60;
var s = parseInt(totalSec % 60, 10);
var result = d+ " days, " + h + " hours, " + m + " minutes and " + s + " seconds to go!";
document.getElementById('timeRemaining').innerHTML = result;
setTimeout(setClock, 1000);
}
setClock();
This method calculates the difference between now and the date in the future each time it is run, thus removing any inaccuracies.
Here is an example: http://jsfiddle.net/t6wUN/1/

Categories