How to run a function at specific time & date?
Solution 1
It's not advised to use setInterval
because it has non-deterministic behaviour - events can be missed, or fire all at once. Time will fall out of sync, too.
The code below instead uses setTimeout
with a one minute period, where each minute the timer is resynchronised so as to fall as closely to the hh:mm:00.000s point as possible.
function surprise(cb) {
(function loop() {
var now = new Date();
if (now.getDate() === 12 && now.getHours() === 12 && now.getMinutes() === 0) {
cb();
}
now = new Date(); // allow for time passing
var delay = 60000 - (now % 60000); // exact ms to next minute interval
setTimeout(loop, delay);
})();
}
Solution 2
On the page where o want to do the check add this
setInterval(function () {
var date = new Date();
if (date.getDate() === 12 && date.getHours() === 10 && date.getMinutes === 0) {
alert("Surprise!!")
}
}, 1000)
Update- add date.getSeconds == 0
to limit it to fire only one at 10:00:00. Thanks to comments below
Solution 3
You can instantiate two Date objects. One for now and one for the next instance of the event. Now is easy: new Date(). For the next instance you can loop through the options till you find one larger than now. Or do some more sophisticated date time wizardry. Compare the getTime() of the both, and then do a setTimeout for the alert.
EDIT: Updated since @Alnitak points out that there's a maximum to the timeout, see setTimeout fires immediately if the delay more than 2147483648 milliseconds.
function scheduleMessage() {
var today=new Date()
//compute the date you wish to show the message
var christmas=new Date(today.getFullYear(), 11, 25)
if (today.getMonth()==11 && today.getDate()>25)
christmas.setFullYear(christmas.getFullYear()+1)
var timeout = christmas.getTime()-today.getTime();
if( timeout > 2147483647 ){
window.setTimeout( scheduleMessage(), 2147483647 )
} else {
window.setTimeout(function() {alert('Ho Ho Ho!'); scheduleMessage()}, timeout)
}
}
Solution 4
You can use something like this
var runned = false;
var d = new Date();
if(d.getDate() == 12 && d.getHours() == 10 && !runned){
//Do some magic
runned = true;
}
If you want some with the minute (and not the whole hour you can add d.getMinutes()
Shannon Hochkins
Passionate about learning new things, constantly working on my own projects to achieve that goal.
Updated on January 15, 2020Comments
-
Shannon Hochkins over 4 years
How can I run a function at a given time and date?
Example: I have a function that needs to run on the 12th of each month at 10AM.
This page will be running 24/7, if this is important.
Obviously I'd have to compare against the current date, but I'm not sure how to check if the current date and time has been matched.
Shannon
-
Alnitak over 10 yearsthis code has bugs, one visible, and one invisible. The invisible bug is that it'll repeatedly show the alert over and over so until the time reaches 10:01.
-
Shannon Hochkins over 10 years@Alnitak, again, you're commenting based on an assumption that I wanted to run the function only once, and also it's not upto the user to completely write the code, it's fairly obvious and simply to clear the interval once it's passed.
-
Alnitak over 10 years@ShannonHochkins if you clear the interval it won't fire next month (assuming the page isn't reloaded between times).
-
Alnitak over 10 yearsfor
== '12'
- the output of.getDate()
is a number -
Kasper Sanguesa-Franz over 10 yearswoops that went a bit fast there, fixed now :)
-
Shannon Hochkins over 10 yearsThat's quite interesting! So I'm assuming that cb, that you're passing to the surprise function, is also a function? Meaning that you run this like so:
surprise(otherFunctionName);
. Do you mind me asking why you do it this way? -
Alnitak over 10 yearsYes, that's right - the "why" is called "separation of concerns" - separating the "when" you want something to happen from the "what".
-
Shannon Hochkins over 10 yearsWhere you're using Modula to calculate the remainder of milliseconds, do you agree it would be more useful putting the minute value in milliseconds as a variable? It would read a bit nicer too I guess, but I do like your solution, it should would quite nicely.
-
flup over 10 yearsI think this way you can be unlucky and miss the exact second you're waiting for, scheduling is not that precise. It could be the first one gets scheduled at 11:59:59.999 and the next one at 12:00:01.000
-
Alnitak over 10 years@ShannonHochkins re: 60s - I'd say at your discretion. Personally I read 60000 and the conversion is instantaneous. Note that even this method is not without risk - if the system clock is adjusted underneath this code the timer could fire when the time isn't quite (yet) 10:00:xx. It's actually pretty hard to mitigate that, though!
-
Shannon Hochkins over 10 yearsCool, no worries @Alnitak, thankyou for your post, just a quick question though, if I was to do this server side rather than client side, is there a way to still have a user interface on the webpage to 'pick' the time, and still correctly start a timer without having the page constantly open? Probably not right..
-
flup over 10 yearsNow take the final step and don't loop, but set only one timeout, to the exact moment you're waiting for. (And end up at my answer ;) )
-
Alnitak over 10 years@flup there are limits as to how far in the future you can do a single
setTimeout
call. -
Alnitak over 10 years@ShannonHochkins that's getting towards the point I was making in my original comments - the page has to be open to do anything, because that's where the JS runs. Now, if you want to specify a time, and then have stuff work if the page is reloaded, you'd have to get into cookies,
localStorage
, that sort of thing, to restore the page's state on reload. -
flup over 10 years@Alnitak I didn't know that, thanks! It seems risky to me to aim for the exact changing of the minute. If you get scheduled a little early, your first check might hit 11:59:59.999 and decide it is not yet time. The second check lands at 12:00:00.001 and decides to wait for another minute. You should probably aim for the halfway point instead.
-
Alnitak over 10 years@flup yeah, one approach is to check for "time < target" changing to "time >= target", but in extremis as you say it'll then wait to 10:01. I'll look at that again.