I'm having a hard time making a loop to extract more than one calendar to a google sheet. The calendars' IDs are in cell P1, the start date is in P7, and the end date is in P8.
The code works fine for one calendar, but when I try to add the j loop on more calendars, my extraction is empty. Can someone figure out what I'm doing wrong?
Thanks for your help.
Here is the code:
var sheet = SpreadsheetApp.getActiveSheet();
// Set filters
var startDate = sheet.getRange('p7').getValue();
var endDate = sheet.getRange('p8').getValue();
var mycal = sheet.getRange('p1').getValue().toString();
var cal = CalendarApp.getCalendarById(mycal);
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(1,1,1,14);
range.setValues(header);
var row=2
for (var j = 0; j< mycal.lengh; j++){
//here we do the things we do once per calander
var cal = CalendarApp.getCalendarById(mycal[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on calulated ROW 2 (i+2)
for (var i=0;i<events.length;i++) {
var row=i+2;
var myformula_placeholder = '';
var details=[[mycal,events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i]. getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]];
var range=sheet.getRange(row,1,1,14);
range.setValues(details);
var cell=sheet.getRange(row,7);
cell.setFormula('=(HOUR(F' +row+ ')+(MINUTE(F' +row+ ')/60))-(HOUR(E' +row+ ')+(MINUTE(E' +row+ ')/60))');
cell.setNumberFormat('.00');
row++;
}
}
}
As #Cooper mentioned, lengh is not an attribute. I made that correction and other changes to the script. Also, I created another sheet where I have a list of calendar ID's, the startDate and endDate. See the script below, I added some comments to explain the changes I made. Make sure to change ranges based on where you have your data.
function calendarFunction() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('B1').getValue(); //Range for startDate
var endDate = sheet2.getRange('B2').getValue(); //Range for endDate
var users = sheet2.getRange('A1:A').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated","MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(1,1,1,14);
range.setValues(header);
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on the next empty row
for (var i=0;i<events.length;i++) {
var myformula_placeholder = '';
var details=[
[users[j].toString(),events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(),
myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(),
events[i].getCreators().toString(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]
];
var lastRow = sheet.getLastRow()+1;
var range=sheet.getRange(lastRow,1,1,14);
range.setValues(details);
var cell=sheet.getRange(lastRow,7);
cell.setFormula('=(HOUR(F' +lastRow+ ')+(MINUTE(F' +lastRow+ ')/60))-(HOUR(E' +lastRow+ ')+(MINUTE(E' +lastRow+ ')/60))');
cell.setNumberFormat('.00');
}
}
}
}
Thanks to the help of this amazing community, I was able to have a script that run so much faster.
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 8 - Calendrier");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k15').getValue(); //Range for startDate
var endDate = sheet2.getRange('k16').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
const data = []
const formulas = [];
const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
var lastRow = sheet.getLastRow()+8;
// Loop through all calendar events found and write them out starting on the next empty row
for (var i = 0; i < events.length; i++) {
var details=
[
events[i].getTitle(),
events[i].getDescription(),
events[i].getLocation(),
events[i].getStartTime(),
events[i].getEndTime()
];
data.push(details);
const rowFormulas =
[
'=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")',
'=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))',
'=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))',
'=IF(G'+lastRow+'="Maladie";1;0)',
'=IF(G'+lastRow+'="Congé";1;0)',
'=IF(G'+lastRow+'="Absence";1;0)'
]
formulas.push(rowFormulas)
lastRow=lastRow+1
}
}
}
sheet.getRange(7,1,headers.length, headers[0].length).setValues(headers)
sheet.getRange(8,1,data.length,data[0].length).setValues(data);
sheet.getRange(8,data[0].length + 1,formulas.length, formulas[0].length).setFormulas(formulas);
sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');
}```
Related
Is there a way to export the colours used in GCal into Gsheets? This is the script I use at the moment to take data from Google Calendar and I want to incorporate a code to bring colours over as well, I'm just not sure if it's possible.
function export_gcal_to_gsheet() {
var mycal = "Email";
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date ());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar2023");
sheet.clearContents();
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(6, 1, 1, 14);
range.setValues(header);
for (var i = 0; i < events.length; i++) {
var row = events.length + 6 - i;
var myformula_placeholder = '';
var details=[[mycal,events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]];
var range=sheet.getRange(row,1,1,14);
range.setValues(details);
var cell=sheet.getRange(row,7);
cell.setFormula('=(HOUR(F' +row+ ')+(MINUTE(F' +row+ ')/60))-(HOUR(E' +row+ ')+(MINUTE(E' +row+ ')/60))');
cell.setNumberFormat('.00');
}
}
Although I'm not sure whether I could correctly understand I want to incorporate a code to bring colours over as well, in your situation how about the following 2 patterns?
In these patterns, the retrieved event color is put to the column "O" as the hex value.
In order to retrieve the color code as the hex, Calendar API is used. So, before you use this script, please enable Calendar API at Advanced Google services.
Pattern 1:
In this pattern, your showing script is simply modified.
function export_gcal_to_gsheet() {
var mycal = "Email";
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar2023");
sheet.clearContents();
var calColor = cal.getColor();
var colors = Calendar.Colors.get().calendar;
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"]]
var range = sheet.getRange(6, 1, 1, 15);
range.setValues(header);
for (var i = 0; i < events.length; i++) {
var color = events[i].getColor();
var row = events.length + 6 - i;
var myformula_placeholder = '';
var details = [[mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), colors[color] ? colors[color].background : calColor]];
var range = sheet.getRange(row, 1, 1, 15);
range.setValues(details);
var cell = sheet.getRange(row, 7);
cell.setFormula('=(HOUR(F' + row + ')+(MINUTE(F' + row + ')/60))-(HOUR(E' + row + ')+(MINUTE(E' + row + ')/60))');
cell.setNumberFormat('.00');
}
}
Pattern 2:
In your script, setValues and setFormula are used in a loop. In this case, the process cost will become high. Ref So, in this pattern, your showing script is modified by reducing the process cost.
function export_gcal_to_gsheet2() {
var mycal = "Email";
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date());
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar2023");
sheet.clearContents();
var calColor = cal.getColor();
var colors = Calendar.Colors.get().calendar;
var header = ["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event", "Color"];
var offset = 6;
var { v, c } = events.reverse().reduce((o, e, i) => {
var color = e.getColor();
var row = offset + i + 1;
var c = colors[color] ? colors[color].background : calColor;
var f = `=(HOUR(F${row})+(MINUTE(F${row})/60))-(HOUR(E${row})+(MINUTE(E${row})/60))`;
o.v.push([mycal, events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), f, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent(), c]);
o.c.push([c]);
return o;
}, { v: [], c: [] });
var values = [header, ...v];
sheet.getRange(6, 1, values.length, values[0].length).setValues(values);
sheet.getRange(7, 7, v.length - 1).setNumberFormat('.00');
sheet.getRange(7, 15, c.length).setBackgrounds(c);
}
In this patten, the column "O" has the hex value and the background colors using the retrieved hex values.
Reference:
Colors: get
I have a google worksheet with multiple sheets, what do I add to this script to target a particular sheet in that worksheet only? At the moment it's just going to the far left-hand sheet. I've tried "getSheetByName("Calendar")", but I get errors so obviously there is more I need to do.
function export_gcal_to_gsheet() {
var mycal = "email";
var cal = CalendarApp.getCalendarById(mycal);
var events = cal.getEvents(new Date("July 01, 2022 00:00:00 UTC"), new Date ());
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(6, 1, 1, 14);
range.setValues(header);
for (var i = 0; i < events.length; i++) {
var row = events.length + 6 - i;
var myformula_placeholder = '';
var details=[[mycal,events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]];
var range=sheet.getRange(row,1,1,14);
range.setValues(details);
var cell=sheet.getRange(row,7);
cell.setFormula('=(HOUR(F' +row+ ')+(MINUTE(F' +row+ ')/60))-(HOUR(E' +row+ ')+(MINUTE(E' +row+ ')/60))');
cell.setNumberFormat('.00');
}
}
Use the function getActiveSpreadsheet() before using getSheetByName()
I have tried your script on my side and changed:
var sheet = SpreadsheetApp.getActiveSheet();
to:
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Calendar");
and your script worked fine and populated the desired sheet with the data provided by the script. I assumed you forgot to use the getActiveSpreadsheet() function which resulted in your script returning an error.
Reference
getSheetByName()
The code below is extracting data from different calendars and writing formulas in the sheet with formulas.push(rowFormulas).
The problem I have is that I can't figure out how to do the loop for the lastrow in the script.
Every time the user change, the lastRow restart at row 8 instead of continuing. Can someone help me to correct my loop? thanks a lot
function export_gcal_to_gsheetLast8(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction - Principal");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
var lastRow = sheet.getLastRow()+8;
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k15').getValue(); //Range for startDate
var endDate = sheet2.getRange('k16').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
const data = []
const formulas = [];
const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on the next empty row
for (var i = 0; i < events.length; i++) {
var details=
[
events[i].getTitle(),
events[i].getDescription(),
events[i].getLocation(),
events[i].getStartTime(),
events[i].getEndTime()
];
data.push(details);
const rowFormulas =
[
'=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")',
'=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))',
'=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))',
'=IF(G'+lastRow+'="Maladie";1;0)',
'=IF(G'+lastRow+'="Congé";1;0)',
'=IF(G'+lastRow+'="Absence";1;0)'
]
lastRow = lastRow +1;
formulas.push(rowFormulas)
}
}
}
sheet.getRange(7,1,headers.length, headers[0].length).setValues(headers)
sheet.getRange(8,1,data.length,data[0].length).setValues(data);
sheet.getRange(8,data[0].length + 1,formulas.length, formulas[0].length).setFormulas(formulas);
sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');
}
I had to move var lastRow = sheet.getLastRow()+8 outside the loop because lastRow was getting reinitialized every loop. (I also had to initialize lastRow to 8: var lastRow = 8)
Here is the correct script:
function export_gcal_to_gsheetPrincipal(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction - Principal");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
var lastRow = 8;
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k1').getValue(); //Range for startDate
var endDate = sheet2.getRange('k2').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
const data = []
const formulas = [];
const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on the next empty row
for (var i = 0; i < events.length; i++) {
var details=
[
events[i].getTitle(),
events[i].getDescription(),
events[i].getLocation(),
events[i].getStartTime(),
events[i].getEndTime()
];
data.push(details);
const rowFormulas =
[
'=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")',
'=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))',
'=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))',
'=IF(G'+lastRow+'="Maladie";1;0)',
'=IF(G'+lastRow+'="Congé";1;0)',
'=IF(G'+lastRow+'="Absence";1;0)'
]
lastRow = lastRow +1;
formulas.push(rowFormulas)
}
}
}
sheet.getRange(7,1,headers.length, headers[0].length).setValues(headers)
sheet.getRange(8,1,data.length,data[0].length).setValues(data);
sheet.getRange(8,data[0].length + 1,formulas.length, formulas[0].length).setFormulas(formulas);
sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');
}
I have this code that extracts calendars from a list of Google calendars.
I have a problem with the maximum execution time.
function export_gcal_to_gsheetLast1(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 1 - Calendrier");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k1').getValue(); //Range for startDate
var endDate = sheet2.getRange('k2').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
var header = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
var range = sheet.getRange(7,1,1,13);
range.setValues(header);
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on the next empty row
for (var i=0;i<events.length;i++) {
var myformula_placeholder = '';
var details=[
[events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(),
myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder,myformula_placeholder]
];
var lastRow = sheet.getLastRow()+1;
var range=sheet.getRange(lastRow,1,1,13);
range.setValues(details);
let formulas = []
for(let i = 0; i < 7; i++){formulas.push('=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))')}}
sheet.getRange(lastRow,6).setFormulas(formulas)
//var cell=sheet.getRange(lastRow,6);
//cell.setFormula('=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))')
cell.setNumberFormat('.00');
var cell=sheet.getRange(lastRow,7);
cell.setFormula('=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")')
var cell=sheet.getRange(lastRow,8);
cell.setFormula('=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")')
var cell=sheet.getRange(lastRow,9);
cell.setFormula('=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))')
var cell=sheet.getRange(lastRow,10);
cell.setFormula('=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))')
var cell=sheet.getRange(lastRow,11);
cell.setFormula('=IF(G'+lastRow+'="Maladie";1;0)')
var cell=sheet.getRange(lastRow,12);
cell.setFormula('=IF(G'+lastRow+'="Congé";1;0)')
var cell=sheet.getRange(lastRow,13);
cell.setFormula('=IF(G'+lastRow+'="Absence";1;0)')
}
}
}
One of the problems is that I'm using methods like setFormula or getRange inside of a loop, this causes a massive call to Spreadsheet service.
This is not recommended by the best practices guides Minimize Call to other service.
So, in order to solve this problem I have to use another recommendation from Best Practices guide, using batch operation.
Instead of using setFormula use setFormulas and delegate to Javascript all the tasks to build the formulas.
I have recived this advice:
All the lines that start with:
var cell=sheet.getRange(lastRow,6); cell.setFormula('=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))')
Should move to something like that:
let formulas = [] for(let i = 0; i < 7; i++){formulas.push(FORMULAS)} sheet.getRange(x,y,nx,ny).setFormulas(formulas)
I have try to change my code using this but without success.
Can someone please give me an example using my code on how I can do this change ?
Thanks a lot !!
You create arrays and push the data in there. Then like you said, you can bulk update it all. Would be something like below. I did not test it and maybe the range is off. But this will get you in the right direction.
function export_gcal_to_gsheetLast1(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 1 - Calendrier");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k1').getValue(); //Range for startDate
var endDate = sheet2.getRange('k2').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
const data = []
const formulas = [];
const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
// Loop through all calendar events found and write them out starting on the next empty row
for (var i = 0; i < events.length; i++) {
var details=
[
events[i].getTitle(),
events[i].getDescription(),
events[i].getLocation(),
events[i].getStartTime(),
events[i].getEndTime()
];
data.push(details);
const rowFormulas =
[
'=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")',
'=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))',
'=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))',
'=IF(G'+lastRow+'="Maladie";1;0)',
'=IF(G'+lastRow+'="Congé";1;0)',
'=IF(G'+lastRow+'="Absence";1;0)'
]
formulas.push(rowFormulas)
}
}
}
sheet.getRange(7,1,1,headers.length, headers[0].length).setValues(headers)
sheet.getRange(8,1,data.length,data[0].length).setValues(data);
sheet.getRange(8,data[0].length + 1,formulas.length, formulas[0].length).setFormulas(formulas);
sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');
}
Thank you again to RemcoE33 for his code. I fixe two mistakes, lastrow was missing and the getRange had an error. Now it is working very well. Thanks a lot !!
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Extraction 8 - Calendrier");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Id Calendriers - Dates Debut et Fin"); //Sheet name where you will have the list of calendar ID's, startDate and endDate
sheet.clear() // If you'll be runnning the script several times, the data will be duplicated so I added this line to clear the sheet before adding the data
// other option would be to create a script to check if data already exists before adding it to the sheet
// Set filters
var startDate = sheet2.getRange('k15').getValue(); //Range for startDate
var endDate = sheet2.getRange('k16').getValue(); //Range for endDate
var users = sheet2.getRange('b3:B').getValues(); //Range where you have the calendar ID's
// Create a header record on the current spreadsheet in cells A1:N1 - Match the number of entries in the "header=" to the last parameter
// of the getRange entry below
const data = []
const formulas = [];
const headers = [["Titre", "Description", "Location", "Début", "Fin", "Heures effectives","Extraction 2","Extraction 3","Heures Planifiées", "Vacances", "Maladie","Congé légal", "Absence"]]
for (var j = 0; j< users.length; j++){
//here we do the things we do once per calander
if (users[j] == ""){
break;
}
else{
var cal = CalendarApp.getCalendarById(users[j]);
var events = cal.getEvents(startDate, endDate);
var lastRow = sheet.getLastRow()+8;
// Loop through all calendar events found and write them out starting on the next empty row
for (var i = 0; i < events.length; i++) {
var details=
[
events[i].getTitle(),
events[i].getDescription(),
events[i].getLocation(),
events[i].getStartTime(),
events[i].getEndTime()
];
data.push(details);
const rowFormulas =
[
'=(HOUR(RIGHT(b' +lastRow+';5))+(MINUTE(RIGHT(b' +lastRow+ ';5))/60))-(HOUR(LEFT(b' +lastRow+ ';5))+(MINUTE(LEFT(b' +lastRow+ ';5))/60))',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");2);"hh:mm");"")',
'=IFERROR(TEXT(INDEX(SPLIT(A'+lastRow+';" ");3);"hh:mm");"")',
'=IF(OR(G'+lastRow+'="Maladie";G'+lastRow+'="Congé";G'+lastRow+'="Absence";G'+lastRow+'="00:00";G'+lastRow+'="Vacances");0;(HOUR(H'+lastRow+')+(MINUTE(H'+lastRow+')/60))-(HOUR(G'+lastRow+')+(MINUTE(G'+lastRow+')/60)))',
'=IF(IFNA(VLOOKUP(D'+lastRow+'; feries;1;FALSE);1)<>1;0;IF(AND(G'+lastRow+'="00:00";H'+lastRow+'="Vacances");0.5;IF(G'+lastRow+'="Vacances";1;0)))',
'=IF(G'+lastRow+'="Maladie";1;0)',
'=IF(G'+lastRow+'="Congé";1;0)',
'=IF(G'+lastRow+'="Absence";1;0)'
]
formulas.push(rowFormulas)
lastRow=lastRow+1
}
}
}
sheet.getRange(7,1,headers.length, headers[0].length).setValues(headers)
sheet.getRange(8,1,data.length,data[0].length).setValues(data);
sheet.getRange(8,data[0].length + 1,formulas.length, formulas[0].length).setFormulas(formulas);
sheet.getRange(8,6,sheet.getLastRow()).setNumberFormat('.00');
}```
I'm using a Google script to extract data from a resource calendar. The script works as intended to extract a single calendar, but I would like to extract multiple resource calendars into 1 sheet. Can someone point me in the right direction? I've looked at creating an array to include multiple calendars into 'mycal', but I couldn't get it to run. Thanks
function export_gcal_to_gsheet(){
var mycal = "engelska.se_xxxx#resource.calendar.google.com";
var cal = CalendarApp.getCalendarById(mycal);
var today = new Date();
var events = CalendarApp.getCalendarById(mycal).getEventsForDay(today);
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(1,1,1,14);
range.setValues(header);
for (var i=0;i<events.length;i++) {
var row=i+2;
var myformula_placeholder = '';
var details=[[mycal,events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]];
var range=sheet.getRange(row,1,1,14);
range.setValues(details);
var cell=sheet.getRange(row,7);
cell.setFormula('=(HOUR(F' +row+ ')+(MINUTE(F' +row+ ')/60))-(HOUR(E' +row+ ')+(MINUTE(E' +row+ ')/60))');
cell.setNumberFormat('.00');
}
}
If you make mycal into an array you will need a second loop to step thru that array and the variable assignment based on mycal will need to be in that loop. the events loop you already have will also need to be inside that loop. Because the number of events in each calendar could be different the best way to maintain the row counter is to declare it before both loops and increment it after you write to a row.
function export_gcal_to_gsheet(){
var mycal = ["engelska.se_xxxx#resource.calendar.google.com",
"calenderaddress2",
"calenderaddress3",
"calenderaddress4"];//note , between address, no , after last
//here we do all the things that need to be done only once.
var today = new Date();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clearContents();
var header = [["Calendar Address", "Event Title", "Event Description", "Event Location", "Event Start", "Event End", "Calculated Duration", "Visibility", "Date Created", "Last Updated", "MyStatus", "Created By", "All Day Event", "Recurring Event"]]
var range = sheet.getRange(1,1,1,14);
range.setValues(header);
var row=2;// this needs to be outside the loops in order to use it as a counter in nested loops
for (var j = 0; j< mycal.lengh; j++){
//here we do the things we do once per calander
var events = CalendarApp.getCalendarById(mycal[j]).getEventsForDay(today);//refer to the calender in mycal based on loop counter
var cal = CalendarApp.getCalendarById(mycal[j]);//refer to the calender in mycal based on loop counter
//incerting a header for each calander would be done here. make sure to increment row
for (var i=0;i<events.length;i++) {
var myformula_placeholder = '';
var details=[[mycal,events[i].getTitle(), events[i].getDescription(), events[i].getLocation(), events[i].getStartTime(), events[i].getEndTime(), myformula_placeholder, ('' + events[i].getVisibility()), events[i].getDateCreated(), events[i].getLastUpdated(), events[i].getMyStatus(), events[i].getCreators(), events[i].isAllDayEvent(), events[i].isRecurringEvent()]];
var range=sheet.getRange(row,1,1,14);
range.setValues(details);
var cell=sheet.getRange(row,7);
cell.setFormula('=(HOUR(F' +row+ ')+(MINUTE(F' +row+ ')/60))-(HOUR(E' +row+ ')+(MINUTE(E' +row+ ')/60))');
cell.setNumberFormat('.00');
row++; //increment row counter.
}
}
}