7

I need to run a Google Apps script three times a day: at 8:00, 12:30, 17:00.

How to do this?

I have already looked at Triggers, and more specifically Time driven:

  • Hour timer, but Every hour, Every 2 hours, Every 4 hours are not adapted here

  • Day timer, but then 8am to 9am is not very precise, I would prefer something more precise, and also 12:30 is not possible

  • Specific time, but then YYYY-MM-DD HH:MM is not adapted to run it daily

From calendar triggers does not seem adapted either.

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Basj
  • 41,386
  • 99
  • 383
  • 673

3 Answers3

13

Use nearMinute() and atHour():

const createTrigger = ([hour, minute])=>
  ScriptApp.newTrigger("myFunction")
  .timeBased()
  .atHour(hour)
  .nearMinute(minute)  
  .everyDays(1) 
  .create();

[[8,0],[12,30],[17,0]].forEach(createTrigger)
TheMaster
  • 45,448
  • 6
  • 62
  • 85
  • Thank you for your answer @TheMaster. PS: where is the natural place to put such "init" / "setup" / "doitonce" code? Just in a `function setup() { }` that you manually run once, in the same .gs file than the main `myFunction` (the one that does the job)? – Basj Mar 20 '20 at 13:33
  • @Bas Yes. You could add ui menu `setup` to run this `setup` function – TheMaster Mar 20 '20 at 13:41
  • Thank you. Where would this UI menu appear (would you have a screenshot)? – Basj Mar 20 '20 at 13:53
  • @Basj Apologies. Menus aren't available to gmail add ons(They're only available to sheets/docs..). May be try [homepages or cards](https://developers.google.com/gsuite/add-ons/gmail) – TheMaster Mar 20 '20 at 14:13
  • @MariosKaramanis One advantage I can think of for your answer seems to be the `everyDays` is not compulsory.A possible solution in my case would be to have frequency `n` infinitely higher -not sure it'll work. – TheMaster Aug 10 '20 at 16:04
  • @TheMaster it will definitely work. You just need to delete the previous triggers everytime you run it. setTrigger() can be ran weekly or monthly or whatever. – Marios Aug 10 '20 at 16:08
9

Although the TheMaster's answer is correct I would like to elaborate a little bit on an alternative approach which might be useful for future readers and different projects.

Let's say you have a list of specific times (24H:mm) you want to schedule every day:

var times = [[9,30],[9,45],[10,00],[12,00]] // 9:30 am, 9:45 am, 10:00 am 12:00pm

which can be completely random, following any sequence you like.

As you can see in the code below, you can run the setTrigger() function , to generate a scheduled trigger of another function function_Triggered() for each element in the aforementioned list. The trigger will have the time provided in times and the date of today.

If you want to perform this task everyday, then you just need to create a daily trigger for setTrigger() and run it before the earliest time in times. In this case, you are generating triggers everyday, and therefore deleteTriggers() is used to delete the previous (disabled) triggers for function_Triggered() that are attached to your project.

function setTrigger() {

deleteTriggers();  
var times = [[9,30],[9,45],[10,00],[12,00]]; // 9:30 am, 9:45 am, 10:00 am 12:00pm
times.forEach(t_el => scheduledTrigger(t_el[0],t_el[1]));
}

function scheduledTrigger(hours,minutes){
  
var today_D = new Date();  
var year = today_D.getFullYear();
var month = today_D.getMonth();
var day = today_D.getDate();
  
pars = [year,month,day,hours,minutes];
  
var scheduled_D = new Date(...pars);
var hours_remain=Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("function_Triggered")
.timeBased()
.after(hours_remain * 60 *60 * 1000)
.create()
}

function deleteTriggers() {
  
var triggers = ScriptApp.getProjectTriggers();
for (var i = 0; i < triggers.length; i++) {
  if (   triggers[i].getHandlerFunction() == "function_Triggered") {
    ScriptApp.deleteTrigger(triggers[i]);
  }
}
}

function function_Triggered() {
 // your function code here
}
Marios
  • 26,333
  • 8
  • 32
  • 52
1

soMario and TheMaster have working solutions, but unfortunately for my use case I needed some tighter tolerances than the + or - 15 minutes!! Which the google app script scheduler 'works' upon.

I used their very inaccurate scheduler to run the below function every 5 minutes. This function will check current time very accurately, it seems so far, and only run the next 'core' function within your desired hours and minutes. A simple if condition addition, using getDay() will add a day of week 'filter'.

function timeCheck() {
  var nowH=new Date().getHours();
  var nowM=new Date().getMinutes();
  Logger.log('Hour: '+nowH+'  Minute: '+nowM)

  if (nowH = 1 && nowM < 12) { getStatus() }
  if (nowH = 10 && (nowM > 15 && nowM < 27)) { getStatus() }

  return
}
R0b0F1SSH
  • 11
  • 1