user2961971
user2961971

Reputation: 287

How to call a function every hour?

I am trying to update information from a weather service on my page. The info should be updated every hour on the hour. How exactly do I go about calling a function on the hour every hour?

I kind of had an idea but I'm not sure of how to actually refine it so it works... What I had in mind was something like creating an if statement, such as: (pseudo code)

//get the mins of the current time
var mins = datetime.mins();    

if(mins == "00"){
    function();
 }

Upvotes: 21

Views: 62746

Answers (7)

vir us
vir us

Reputation: 10765

Here is my pair of setIntervalWithDelay and clearIntervalWithDelay that one can use like this:

let descriptor = setIntervalWithDelay(callback, 60 * 60 * 1000, nextHourDelay)

And when you are done with it:

clearIntervalWithDelay(descriptor)

Here is my implementation of the functions:

const setIntervalWithDelay = (callback, interval, delay = 0) => {
    let descriptor = {}
    descriptor.timeoutId = setTimeout(() => {
        if(!descriptor.timeoutId){
            return
        }
        descriptor.timeoutId = null
        callback()
        descriptor.intervalId = setInterval(callback, interval)
    }, delay)
    return descriptor
}

export const clearIntervalWithDelay = (descriptor) => {
    if(!isObject(descriptor) || (!descriptor.timeoutId && !descriptor.intervalId)){
        console.warn("clearIntervalWithDelay: Incorrect descriptor. Please pass an object returned by setIntervalWithDelay. Skipping this call.")
        return
    }
    if(descriptor.timeoutId){
        clearTimeout(descriptor.timeoutId)
        descriptor.timeoutId = null
        console.log("clearIntervalWithDelay: stopped during delay.")
    }
    if(descriptor.intervalId){
        clearInterval(descriptor.intervalId)
        descriptor.intervalId = null
        console.log("clearIntervalWithDelay: stopped during interval repeat.")
    }
}

One example of using dayjs to get the delay for the next hour:

let nextHour = dayjs().second(0).millisecond(0).add(1, "hour")
let nextHourDelay = nextHour.diff(dayjs())

Upvotes: 0

Serge Stroobandt
Serge Stroobandt

Reputation: 31658

Repeat at specific minute past the hour

This counter is a little bit more versatile; it allows to perform a task repeatedly always at the same minute past the hour (e.g. 37 minutes past the hour), and this with up to millisecond precision.

The precision of this timer is derived from its recursion. At every recursion, the millisecond time to the next minute gets recalculated. This prevents time lag over long periods.

The % sign refers to the modulo operator.

function minuteCount(minutesAfterHour) {

    const now          = new Date();
    const hours        = now.getHours();
    const minutes      = now.getMinutes();
    const seconds      = now.getSeconds();
    const milliseconds = now.getMilliseconds();

    waitUntilNextMinute = setTimeout(minuteCount, 60000 - seconds * 1000 - milliseconds);

    if(minutes % 60 === minutesAfterHour) {
        doSomethingHourly();
    }

}

minuteCount(37);

Finally, timers are best kept away from the main thread. They are best run from within a web worker, as explained here. This works perfectly with unfocused tabs in desktop browsers.

However, dedicated web workers on Chrome for Android are put to sleep about 5 minutes after moving the main client to the background.

Upvotes: 2

HaukurHaf
HaukurHaf

Reputation: 13816

Here is what should work (JSFiddle):

function tick() {
  //get the mins of the current time
  var mins = new Date().getMinutes();
  if (mins == "00") {
    alert('Do stuff');
  }
  console.log('Tick ' + mins);
}

setInterval(tick, 1000);

Upvotes: 13

Steven Koch
Steven Koch

Reputation: 797

// ... call your func now
let intervalId;
let timeoutId = setTimeout(() => {
  // ... call your func on end of current hour
  intervalId = setInterval(() => {
     // ... call your func on end of each next hours
  }, 3600000);
}, ((60 − moment().minutes()) × 60 × 1000) - (moment().second() * 1000));

Upvotes: 0

Igor
Igor

Reputation: 34021

You want to check out setInterval: https://developer.mozilla.org/en-US/docs/Web/API/Window.setInterval

It's a little hard to tell what you're trying to call with your code, but it would be something in the form of:

function callEveryHour() {
    setInterval(yourFunction, 1000 * 60 * 60);
}

If you want it every hour, try something like:

var nextDate = new Date();
if (nextDate.getMinutes() === 0) { // You can check for seconds here too
    callEveryHour()
} else {
    nextDate.setHours(nextDate.getHours() + 1);
    nextDate.setMinutes(0);
    nextDate.setSeconds(0);// I wouldn't do milliseconds too ;)

    var difference = nextDate - new Date();
    setTimeout(callEveryHour, difference);
}

Now, this implementation checks the time once, sets the delay (or calls the function immediately), and then relies on setInterval to keep track after that. An alternative approach may be to poll the time every x many seconds/minutes, and fire it .getMinutes() == 0 instead (similar to the first part of the if-statement), which may sacrifice (marginal) performance for (marginal) accuracy. Depending on your exact needs, I would play around with both solutions.

Upvotes: 33

ZER0
ZER0

Reputation: 25332

What you probably want is something like that:

var now = new Date();
var delay = 60 * 60 * 1000; // 1 hour in msec
var start = delay - (now.getMinutes() * 60 + now.getSeconds()) * 1000 + now.getMilliseconds();

setTimeout(function doSomething() {
   // do the operation
   // ... your code here...

   // schedule the next tick
   setTimeout(doSomething, delay);
}, start);

So basically the first time the user get the access, you need to know what is the delay in millisecond to the next "hour". So, if the user access to the page at 8:54 (with 56 seconds and 123 milliseconds), you have to schedule the first execution after around 3 minutes: after the first one is done, you can call it every "hour" (60 * 60 * 1000).

Upvotes: 11

Asenar
Asenar

Reputation: 7030

EDIT: Oops, I didn't see the " o' clock" things, so I edit my answer :

var last_execution = new Date().getTime();
function doSomething(force){
  var current_time = new Date().getTime();
  if (force || (current_time.getMinutes() == 0)
  {
    last_execution = current_time;
    // something
    // ...
  }
  setTimeout(doSomething(false), 1000);
}
// force the first time
doSomething(true); 

Upvotes: 0

Related Questions