This is a sample script for executing a function with the minutes timer in the specific times using Google Apps Script. For example, when this sample script is used, the following situation can be achieved.
- Execute a function every 10 minutes only in 09:00 - 12:00 and 15:00 - 18:00 for the weekday.
When the above situation is shown as an image, it becomes as follows.
In the above sample situation, a function is run every 10 minutes in the green ranges of 09:00 - 12:00 and 15:00 - 18:00.
In the current specification, the maximum number of triggers is 20 for a script. Ref When the above script is used, 6 triggers are used. So the limitation is not affected.
Flow
The flow of this script is as follows. In this case, it will explain the flow using the above sample situation of “Execute a function every 10 minutes only in 09:00 - 12:00 and 15:00 - 18:00 for the weekday.”.
-
Install a base trigger.
- The sample function name is
initTriggers
. - This function is executed at 00:00 tomorrow. By this, the script is run from tomorrow.
- When today supposes
2021-09-01
, the function is executed at2021-09-02T00:00:00
.
- The sample function name is
-
When
initTriggers
is run at2021-09-02T00:00:00
, 4 triggers for executing the functions at2021-09-02T09:00:00
,2021-09-02T12:00:00
,2021-09-02T15:00:00
and2021-09-02T18:00:00
are installed. And, the trigger for executinginitTriggers
is installed for2021-09-03T00:00:00
.- For example, when today is Saturday and Sunday, above 4 triggers are not installed. By this, on Saturday and Sunday, the script is not run.
-
For example, when the trigger of
2021-09-02T09:00:00
is run, the trigger for executing every 10 minutes is installed and when the time is2021-09-02T12:00:00
, the trigger is deleted. About2021-09-02T15:00:00
and2021-09-02T18:00:00
, the same situation is also run. -
When it’s
2021-09-03T00:00:00
,initTriggers
is run, and then, the above 2 and 3 flows are run.
By this, the function can be executed with the minutes timer in specific times.
Usage
1. Sample script
Please copy and paste the following script to the script editor of Google Apps Script. And, please set the variable of runTime
and set your script in main()
. And then, please run the function of runOnlyOneTime
. By this, the trigger is run from 00:00 in tomorrow.
And, when the day is Saturday and Sunday under weekday: true
, the script is run on the weekday. When weekday: false
is used, the script is run only Saturday and Sunday.
// Please set the condition of the triggers.
const runTimes = {
cycle: 10, // Unit is minute.
functionName: "main",
weekday: true, // When this property is existing, you can run functionName at weekday or weekend. When this property is not used, the function is run every day.
times: [
{ start: "09:00", end: "12:00" },
{ start: "15:00", end: "18:00" },
],
};
// Please set your Web Apps URL.
const webAppsUrl = "https://script.google.com/macros/s/###/exec"; // or https://script.google.com/macros/s/###/dev of developer mode
// Please set your script you want to execute with the minutes timer in the specific times.
function main() {
//
// do something
//
}
// When you run this function only one time, your main script will be run by the time-driven triggers.
// --- PLEASE RUN THIS FUNCTION ONLY ONE TIME! ---
function runOnlyOneTime() {
fetchWebApps_(`${webAppsUrl}?func=${"setRunEveryDay"}`);
}
//
// --- Script for installing the triggers --- Begin
//
// When v8 runtime is used, when the trigger is set from the function executing by a trigger, the trigger is disabled. This is the recognized bug. But unfortunately, this has still not been resolved. (September 21, 2021)
// https://issuetracker.google.com/issues/150756612
// https://issuetracker.google.com/issues/142405165
const doGet = (e) => {
const func = e.parameter.func;
if (func == "setRunEveryDay") {
setRunEveryDay_();
} else if (func == "initTrigger") {
initTriggers();
} else if (func == "StartEndTriggers") {
if (
!runTimes.hasOwnProperty("weekday") ||
(runTimes.hasOwnProperty("weekday") &&
runTimes.weekday === true &&
checkWeekday_()) ||
(runTimes.hasOwnProperty("weekday") &&
runTimes.weekday === false &&
!checkWeekday_())
) {
convertStrToDateObj_().times.forEach(({ start, end }) => {
ScriptApp.newTrigger("startTrigger").timeBased().at(start).create();
ScriptApp.newTrigger("endTrigger").timeBased().at(end).create();
});
}
} else {
throw new Error("No query parameter.");
}
return ContentService.createTextOutput();
// DriveApp.createFile() // This is used for automatically detecting the scopes for requesting to Web Apps. Please don't remove this comment line.
};
const fetchWebApps_ = (url) =>
UrlFetchApp.fetch(url, {
headers: { authorization: "Bearer " + ScriptApp.getOAuthToken() },
});
// Below script is used for installing triggers.
const initTriggers = (_) => {
deleteTriggers_([
runTimes.functionName,
"startTrigger",
"endTrigger",
"initTriggers",
]);
deleteTriggers_([
runTimes.functionName,
"startTrigger",
"endTrigger",
"initTriggers",
]);
fetchWebApps_(`${webAppsUrl}?func=${"StartEndTriggers"}`);
fetchWebApps_(`${webAppsUrl}?func=${"setRunEveryDay"}`);
};
const setRunEveryDay_ = (t = new Date()) => {
t.setDate(t.getDate() + 1);
t.setHours(0);
t.setMinutes(0);
t.setSeconds(0);
ScriptApp.newTrigger("initTriggers").timeBased().at(t).create();
};
const startTrigger = (_) => {
const obj = convertStrToDateObj_();
ScriptApp.newTrigger(obj.functionName)
.timeBased()
.everyMinutes(obj.cycle)
.create();
};
const endTrigger = (_) => deleteTriggers_([runTimes.functionName]);
const convertStrToDateObj_ = (now = new Date()) => {
now = now.toISOString();
runTimes.times = runTimes.times.map((obj) => {
const [sh, sm] = obj.start.split(":");
const [eh, em] = obj.end.split(":");
const d1 = new Date(now);
const d2 = new Date(now);
d1.setHours(sh);
d1.setMinutes(sm);
d1.setSeconds(0);
d2.setHours(eh);
d2.setMinutes(em);
d2.setSeconds(0);
obj.start = new Date(d1.getTime() - runTimes.cycle * 60 * 1000);
obj.end = new Date(d2.getTime() + runTimes.cycle * 60 * 1000);
return obj;
});
return runTimes;
};
const deleteTriggers_ = (functions) =>
ScriptApp.getScriptTriggers().forEach((t) => {
if (functions.includes(t.getHandlerFunction())) ScriptApp.deleteTrigger(t);
});
const checkWeekday_ = (d = new Date()) => ![0, 6].includes(d.getDay());
//
// --- Script for installing the triggers --- End
//
2. Deploy Web Apps
This sample script used Web Apps. Because when v8 runtime is used, when the trigger is set from the function executing by a trigger, the trigger is disabled. This is the recognized bug. But unfortunately, this has still not been resolved. (September 21, 2021) But, when the trigger is installed by Web Apps, no issue occurs. So, please deploy Web Apps.
The detail information can be seen at the official document and my report.
- On the script editor, at the top right of the script editor, please click “click Deploy” -> “New deployment”.
- Please click “Select type” -> “Web App”.
- Please input the information about the Web App in the fields under “Deployment configuration”.
- Please select “Me” for “Execute as”.
- This is the important of this workaround.
- Please select “Only myself” for “Who has access”.
- Please click “Deploy” button.
- Copy the URL of Web App. It’s like
https://script.google.com/macros/s/###/exec
.- When you modified the Google Apps Script, please modify the deployment as new version. By this, the modified script is reflected to Web Apps. Please be careful this.
- You can see the detail of this at the report of “Redeploying Web Apps without Changing URL of Web Apps for new IDE”.
As a point for developing, in my environment, I have used this URL as the developer mode like https://script.google.com/macros/s/###/dev
. By this, even when the script is modified, it is not required to update the version of Web Apps.
3. Run script
When you use this script, please run the function of runOnlyOneTime()
. By this, the 1st trigger is installed at 00:00 of tomorrow. When it’s 00:01 of tomorrow, initTriggers()
is run and triggers for executing main()
are installed.
References
- Time-driven triggers
- Current limitations in Quotas for Google Services
- Web Apps
- Taking advantage of Web Apps with Google Apps Script
Updated:
From RubĂ©n’s answer of this thread, it seems that when the interval time for the next run is more than 60 seconds, even when Web Apps is not used, the time-driven trigger can be directly installed.