Alex McDaid
Alex McDaid

Reputation: 269

javascript run a function every quarter hour at 00, 15, 30 ,45

I have the following code taken from stack overflow:

   function doSomething() {
       var d = new Date(),
       h = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() + 1, 0, 0, 0),
       e = h - d;
       window.setTimeout(doSomething, e);

       //code to be run
       alert("On the hour")
    }
    doSomething(); 

This works perfectly and produces an alert every hour on the hour. I would like the function to run every 15 minutes, at 00, 15, 30 and 45

Upvotes: 8

Views: 5445

Answers (4)

awbergs
awbergs

Reputation: 952

Look at what the function is doing. You have a variable h getting set to one hour after the current time.

//Gets the current date
var d = new Date() 

//Note the +1
h = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours() + 1, 0, 0, 0)

Each parameter in the Date constructor corresponds to a time interval

new Date(year, month, day, hours, minutes, milliseconds)

Using this newly discovered bit of knowledge we can deduce that instead of adding one to the current hour, we need to add 15 minutes to the current time. The problem is that we can't just blindly add 15 minutes and think that we are all set because what we really want is to start on a quarter hour interval and only execute again on the next quarter hour.

In order to solve this conundrum we have to find out how far away we are from the next quarter interval, and set that as our timeout value.

var d = new Date();

var currentSeconds = d.getMinutes() * 60 + d.getSeconds();

var secondsFromQuarter = 900 - currentSeconds % 900;

Now we know how many seconds we need to wait to call doSomething, but we must convert it to milliseconds.

var millisecondsFromQuarter = minutesFromQuarter * 1000;

Voila! From here we can call the setTimeout just like above with our millisecondsFromQuarter value:

window.setTimeout(doSomething, millisecondsFromQuarter);

Disclaimer

This will be accurate to the second. If accuracy is needed to the millisecond then you would simply compare the millisecond value like so:

var currentMilliseconds = d.getMinutes() * 60 * 1000 + d.getSeconds() * 1000 + d.getMilliseconds();

var MillisecondsFromQuarter = 900000 - currentSeconds % 900000;

Disclaimer #2

I up-voted @kamituel's answer because it effectively does the same thing in a much cleaner way visually. I'm not sure which is better for performance but it's probably 6:6

Upvotes: 4

Scott Mermelstein
Scott Mermelstein

Reputation: 15397

This is a little trickier than others presented. You don't want 15 minutes from now, you want 15 minutes on the mark, starting with the next most recent. There are lots of ways to do it, but this one is what first jumps to my mind:

function doSomething() {
   var d = new Date();
   var minutes = 15 - d.getMinutes() % 15; // the number of minutes till the next 15.
   window.setTimeout(doSomething, minutes * 60 * 1000);

   //code to be run
   alert("On the quarter-hour")
}
doSomething(); 

Give it a try. :-)

Edit

The above code is the simplest, but will have issues since it only looks at the minutes. It can drift by up to 59.999 seconds, and depending on processor load, may even show up occassionally on a 1, 16, 31, or 46. To make sure that doesn't happen, you do need to subtract:

function doSomething() {
   var d = new Date();
   var minutes = 15 - d.getMinutes() % 15; // the number of minutes till the next 15.
   var h = new Date(d.getYear(), d.getMonth(), d.getDay(), d.getHours(), d.getMinutes() + minutes, 0);
   var e = h-d;
   window.setTimeout(doSomething, e);

   //code to be run
   alert("On the quarter-hour")
}
doSomething(); 

This keeps you precise to the second, while my original post was only precise to the minute.

Upvotes: 5

IdanHen
IdanHen

Reputation: 266

 function doSomething() {
   var d = new Date(),
   current_minutes = d.getMinutes(),
   current_hour = d.getHours(),
   next_min_hit = 0;

   if ( current_minutes >= 0 && current_minutes < 15 )
      next_min_hit = 15;
   if ( current_minutes >= 15 && current_minutes < 30 )
      next_min_hit = 30;
   if ( current_minutes >= 30 && current_minutes < 45 )
      next_min_hit = 45;
   if ( current_minutes >= 45 && current_minutes < 59 ){
      next_min_hit = 0;
      current_hour++;
   }
   var h = new Date(d.getFullYear(), d.getMonth(), d.getDate(), current_hour, next_min_hit , 0, 0),
   e = h - d;
   window.setTimeout(doSomething, e);

   //code to be run
   alert("On the hour")
}
doSomething(); 

Upvotes: -1

kamituel
kamituel

Reputation: 35970

Get the time of the next even 15 minutes by:

(d.getMinutes() - (d.getMinutes() % 15)) + 15

On example when you invoke doSomething() at 13:43, it will run next time at 13:45:

( 43 - (43 % 15) + 15 ) = ( 43 - 13 + 15 ) = 45

Then it will run as expected: 14:00, 14:15 and so on...

Complete code:

function doSomething() {
     var d = new Date(),
         h = new Date(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), (d.getMinutes() - (d.getMinutes() % 15)) + 15, 0, 0),
         e = h - d;
     window.setTimeout(doSomething, e);

     console.log('run');
 }
 doSomething();

Upvotes: 14

Related Questions