I've implemented a script in my google sheet that grabs gcal calendar info and displays it in various tabs of the sheet. However, the end date of each event as displayed in the sheet is one day LONGER than what is displayed in the calendar itself. Code below. Through logging, I can't figure out why its happening. Is there something to do with the formatting of the date? Any help would be appreciated!
function populateAllTabs() {
var id = "[MY CAL ID HERE]"; // id is currently set to bookings calendar. NB: Takes a string!
var cal = CalendarApp.getCalendarById(id);
var startPeriod = new Date('January 1, 2020');
startPeriod.setHours(0, 0, 0, 0);
var endPeriod = new Date(startPeriod);
endPeriod.setDate(endPeriod.getDate() + 365); // looks for all events in the range one year
var ss = SpreadsheetApp.getActive();
for(var n in ss.getSheets()){// loop over all tabs in the spreadsheet
var sheet = ss.getSheets()[n];// look at every sheet in spreadsheet
var name = sheet.getName();//get name
if(name != 'List'){
var gig = sheet.getRange(1,1);
var gigName = gig.getValue();
var events = cal.getEvents(startPeriod, endPeriod, {search:gigName});
// find the title of each event in the calendar
var eventTitles = [];
for (var i = 0; i < events.length; i++) {
eventTitles.push([events[i].getTitle()]);
}
// find the start date of each event in the calendar
var starttime = [];
for (var i = 0; i < events.length; i++) {
starttime.push([Utilities.formatDate(events[i].getStartTime(), "GMT", "MM/dd/yy")]);
}
// find the end date of each event in the calendar
var endtime = [];
for (var i = 0; i < events.length; i++) {
endtime.push([Utilities.formatDate(events[i].getEndTime(), "GMT", "MM/dd/yy")]);
}
var cell = sheet.getRange("B3");
cell.setValue(starttime + ' - ' + endtime);
}
}
}
This works for me. No problem with the dates
function populateAllTabs() {
var cal = CalendarApp.getCalendarById('id');
var startyear=2019;
var startPeriod = new Date(startyear,0,1);
var endPeriod = new Date(startyear+1,1,1);
var ss=SpreadsheetApp.getActive();
var shts=ss.getSheets();
for(var n=0;n<shts.length;n++){
var sheet=shts[n];
var name=sheet.getName();
if(name!='List'){
var gigName = sheet.getRange(1,1).getValue();
var ev=cal.getEvents(startPeriod, endPeriod, {search:gigName});
var gigs=[]
for (var i=0;i< ev.length;i++) {
gigs.push([ev[i].getTitle(),Utilities.formatDate(new Date(ev[i].getStartTime()),Session.getScriptTimeZone(),"MM/dd/yy"),Utilities.formatDate(new Date(ev[i].getEndTime()),Session.getScriptTimeZone(),"MM/dd/yy")]);
}
if(gigs) {
sheet.getRange(3,2,gigs.length,gigs[0].length).setValues(gigs);
}
}
}
}
Related
I have a template sheet for group data entry. Most of the sheet is free entry, but there are title rows that I don't want edited so I have them protected. We have one of these tabs for each day of the month and a new Sheet for each month.
I want to copy the template 30-31 times depending on the month and have the title of the sheet be the corresponding date (MM.dd.yy ie: 11.02.20). I have the Date set in A2 (ie: 11/01/2020).
So far I tried combining a protections and a date change, but I keep getting variable errors and then sometimes it double creates sheets (like 11.06.20 and then stops).
This is the code I've tried (and edited and moved around a few times).
function duplicateSheetWithProtections() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getActiveSheet();
var dateCell = "A2";
sheet = ss.getSheetByName('Template.01.20');
sheet2 = sheet.copyTo(ss).setName('11..20');
var N = 30;
var startDate = new Date(s.getRange(dateCell).getValue());
var day = startDate.getDate();
var month = startDate.getMonth();
var year = startDate.getFullYear();
for (var i = 0; i < N; i++) {
var asn = s.copyTo(ss);
var thisSheetDate = new Date(year, month, day+(i+1));
asn.getRange(dateCell).setValue(thisSheetDate);
asn.setName(Utilities.formatDate(thisSheetDate, "GMT-08:00", "MM.dd.yy"));
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var i = 0; i < protections.length; i++) {
var p = protections[i];
var rangeNotation = p.getRange().getA1Notation();
var p2 = sheet2.getRange(rangeNotation).protect();
p2.setDescription(p.getDescription());
p2.setWarningOnly(p.isWarningOnly());
if (!p.isWarningOnly()) {
p2.removeEditors(p2.getEditors());
p2.addEditors(p.getEditors());
// p2.setDomainEdit(p.canDomainEdit());
}
}
}
}
Any help would be greatly appreciated.
Also, new to this and if you couldn't tell, kind of a noob. So any references to help grow would be awesome. Thanks!
Issue:
You are using the same variable (i) for two different for loops, one nested inside the other. This is messing up with your dates, causing the error you're getting.
Solution:
Change the variable name of the inner loop (for example, to j):
for (var j = 0; j < protections.length; j++) {
var p = protections[j];
Further issues:
You are setting protections to sheet2, which corresponds to the copied sheet with name 11..20, but not to the rest of sheets (actually, I'm not sure what's the point of making this copy, so I'd just delete the line sheet2 = sheet.copyTo(ss).setName('11..20');). In order to set the protections to each copied sheet, you should use asn instead:
var p2 = asn.getRange(rangeNotation).protect();
Since you want to copy the file named Template.01.20, there is no point in getting the active sheet and storing it in s. I'd just change the mentions of s to sheet (and remove the line var s = ss.getActiveSheet();, since it's not needed):
var startDate = new Date(sheet.getRange(dateCell).getValue());
// ...
var asn = sheet.copyTo(ss);
Since the number of sheets to copy depends on how many days the month has, I'd suggest you to dynamically find that number. You can do that using the following function, for example (credits to Juan Mendes):
function getDaysInMonth(year, month, day) {
var date = new Date(year, month, day);
var days = [];
while (date.getMonth() === month) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
return days;
}
Which you could then call in your main function:
var dates = getDaysInMonth(year, month, day + 1);
for (var i = 0; i < dates.length; i++) {
var asn = sheet.copyTo(ss);
var thisSheetDate = dates[i];
Code sample:
Therefore, your code could be something like this instead:
function duplicateSheetWithProtections() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var dateCell = "A2";
var sheet = ss.getSheetByName('Template.01.20');
var startDate = new Date(sheet.getRange(dateCell).getValue());
var day = startDate.getDate();
var month = startDate.getMonth();
var year = startDate.getFullYear();
var dates = getDaysInMonth(year, month, day + 1);
for (var i = 0; i < dates.length; i++) {
var asn = sheet.copyTo(ss);
var thisSheetDate = dates[i];
asn.getRange(dateCell).setValue(thisSheetDate);
asn.setName(Utilities.formatDate(thisSheetDate, "GMT-08:00", "MM.dd.yy"));
var protections = sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE);
for (var j = 0; j < protections.length; j++) {
var p = protections[j];
var rangeNotation = p.getRange().getA1Notation();
var p2 = asn.getRange(rangeNotation).protect();
p2.setDescription(p.getDescription());
p2.setWarningOnly(p.isWarningOnly());
if (!p.isWarningOnly()) {
p2.removeEditors(p2.getEditors());
p2.addEditors(p.getEditors());
}
}
}
}
function getDaysInMonth(year, month, day) {
var date = new Date(year, month, day);
var days = [];
while (date.getMonth() === month) {
days.push(new Date(date));
date.setDate(date.getDate() + 1);
}
return days;
}
I am using as a master tracking spreadsheet so all new details added after the calendar event import get mixed up when a new event is added to the sheet. HELP. I need to keep the events and new columns of data in the same row. I have 14 rows of data.
function importCalendar(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Calendar Import'); //Target sheet for events
var calendarName = sheet.getRange('C2').getValue(); //name of calendar ex. calendar#gmailcom
var start = sheet.getRange('C3').getValue(); //to date
var end = sheet.getRange('C4').getValue(); //from date
var calendar = CalendarApp.getCalendarById(calendarName);
if(calendar) {var calendarId = calendar.getId();}
if(!calendar) {
var calendar = CalendarApp.getCalendarsByName(calendarName)[0];
var calendarId = calendarName;
}
var events = calendar.getEvents(start, end);
var eventDetails = [];
for(var i = 0; i<events.length; i++){
eventDetails.push([events[i].getLocation(), events[i].getTitle(), events[i].getStartTime(),
events[i].getDescription()]);
}
//write calendar details to spreadsheet and where my problem is//
var startRow = 8;
var startCol = 2;
for(var j = 0; j<eventDetails.length; j++){
var tempRange = sheet.getRange(startRow+j, startCol, 1, eventDetails[j].length);
var eventArray = Array(eventDetails[j]);
tempRange.setValues(eventArray);
}
return eventDetails;
}
I am writing a script to delete every event from each of my calendars in a single month. My code:
function myFunction() {
var year = 2018;
var month = 11;
var fromDate = new Date(year,month,1,0,0,0);
var toDate = new Date(year,month,28,0,0,0);
var calendars = ['cal1', 'cal2', 'cal3','cal4','cal5','cal6'];
for (var x = 0; x < calendars.length; x++) {
var calendar = CalendarApp.getCalendarsByName(calendars[x])[0];
var events = calendar.getEvents(fromDate, toDate);
for(var i = 0; i < events.length; i++){
var ev = events[i];
ev.deleteEvent();
}
}
}
When I run my code I get the following error:
TypeError: Cannot call method "getEvents" of undefined. (line 13, file
"Code")
Am I not running getEvents() on a calendar object? Why is this code give me an error when it tries to use that function?
Try this:
I removed the deleteEvents because I don't want to delete my events. But this code produced Calendar Name, Event Title, Event StartTime and Event EndTime for all event in the given period.
function myFunction() {
var year = 2018;
var month = 11;
var fromDate = new Date(year,month,1,0,0,0);
var toDate = new Date(year,month,28,0,0,0);
var calendars = ['You'll have to put your calendar names back in here.']
var html='';
for (var x=0;x<calendars.length;x++) {
var calendar = CalendarApp.getCalendarsByName(calendars[x]);
var events = calendar[0].getEvents(fromDate, toDate);
for(var i = 0; i < events.length; i++){
var ev = events[i];
html+=Utilities.formatString('<br />Calendar Name: %s<br />EventTitle: %s<br />EventStartTime: %s<br />Event End Time: %s',calendar[0].getName(),events[i].getTitle(),events[i].getStartTime(),events[i].getEndTime() );
}
}
var userInterface=HtmlService.createHtmlOutput(html);
SpreadsheetApp.getUi().showModelessDialog(userInterface, 'Calendar Events')
}
I am trying to write a script that deletes all the events from every calendar in a certain month. Based on this method it looks like I am using the correct code, but every time I try to run this code, I get the error,
TypeError: Cannot find function getEvents in object Calendar. (line 17, file "Code")
My code is:
function myFunction() {
var year = 2018;
var month = 11;
var fromDate = new Date(year,month,1,0,0,0);
var toDate = new Date(year,month,28,0,0,0);
var calendars = ['def', 'Appointments', 'Chores', 'Contacts', 'Dates', 'Errand', 'IMPORTANT!!', 'Scheduling','Time-Sensitive', 'TV Show', 'Work'];
for (var x = 0; x < calendars.length; x++) {
var calendar = CalendarApp.getCalendarsByName(calendars[x])[0];
var events = calendar.getEvents(fromDate, toDate);
for (var i = 0; i < events.length; i++) {
var ev = events[i];
ev.deleteEvent();
}
}
}
Does anyone know what I am doing wrong?
The problem is that CalendarApp.getCalendarsByName(calendars[x]); returns an array. To access even the first and only element in the array you can do this:
var calendar=CalendarApp.getCalendarsByName(calendars[x])[0]; so that now the variable calendar is now a calendar and not an array of calendars.
Here's the form the script script I'm using:
function myFunction101() {
var year=2018;
var month=11;
var fromDate=new Date(year,month,1,0,0,0);
var toDate=new Date(year,month,28,0,0,0);
var calendars=['', ''];//using my calendars
for(var x=0;x<calendars.length;x++) {
var calendar=CalendarApp.getCalendarsByName(calendars[x])[0];
var events=calendar.getEvents(fromDate, toDate);
for(var i = 0; i < events.length; i++){
var ev = events[i];
Logger.log(ev.getTitle());
//ev.deleteEvent();
}
}
}
I have been trying for days now, reading other posts, playing with other scripts that have been close to the same purpose and nothing works. I am trying to make a script that will take information from a web based google form, along with a month/day and turn it into a re-occuring event in the Calendar.
It is finally posting to the Calendar NOW but every event comes up undefined under December 31, 2015 - with no further information, altho at least it is reoccurring.
Any help would be greatly appreciated as I try to understand this coding and how to do it. Thank you!
//this is the ID of the calendar to add the event to, this is found on the calendar settings page of the calendar in question
var calendarId = "id#group.calendar.google.com";
//below are the column ids of that represents the values used in the spreadsheet (these are non zero indexed)
var startDtId = 5;
var endDtId = 5;
var titleId = 2;
var descId = 3;
var formTimeStampId = 1;
function getLatestAndSubmitToCalendar() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
var lr = rows.getLastRow();
var startDt = sheet.getRange(lr,startDtId,1,1).getValue();
//set to first hour and minute of the day.
// startDt.setHours(0);
// startDt.setMinutes(00);
var endDt = sheet.getRange(lr,endDtId,1,1).getValue();
//set endDt to last hour and minute of the day
// endDt.setHours(23);
// endDt.setMinutes(59);
// var subOn = "Submitted on :"+sheet.getRange(lr,formTimeStampId,1,1).getValue();
var desc = sheet.getRange(lr,descId,1,1).getValue();
var title = sheet.getRange(lr,titleId,1,1).getValue();
createAllDayEvent(calendarId,title,startDt,endDt,recurrence,loc,desc);
}
function createAllDayEventSeries(calendarId,title,startDt,endDt,recurrence,loc,desc) {
var cal = CalendarApp.getCalendarById('id#group.calendar.google.com');
var start = new Date(startDt);
var end = new Date(endDt);
var loc = descId;
var desc = "Happy Birthday "+titleId+" of "+descId;
// Creates a rule that recurs every week for ten weeks.
var recurrence = CalendarApp.newRecurrence().addYearlyRule();
var event = cal.createAllDayEventSeries(title, start, recurrence, {
description : desc,
location : loc
});
};
I created a form and tested with the following code:
// Column data constants
var nameCol = 2;
var birthdayCol = 3;
var descriptionCol = 4;
var locationCol = 4;
var calendarId = '[id]#group.calendar.google.com';
/* Send Confirmation Email with Google Forms */
function Initialize() {
var triggers = ScriptApp.getProjectTriggers();
for (var i in triggers) {
ScriptApp.deleteTrigger(triggers[i]);
}
ScriptApp.newTrigger("CreateCalendarEvent")
.forSpreadsheet(SpreadsheetApp.getActiveSpreadsheet())
.onFormSubmit()
.create();
}
function createEvent() {
var ss = SpreadsheetApp.getActiveSheet();
var rows = ss.getDataRange();
var lr = rows.getLastRow();
var start = ss.getRange(lr,birthdayCol,1,1).getValue();
start.setHours(0);
start.setMinutes(00);
var title = ss.getRange(lr,nameCol,1,1).getValue() + " Birthday";
var desc = ss.getRange(lr,descriptionCol,1,1).getValue();
var loc = ss.getRange(lr,locationCol,1,1).getValue();
var recurrence = CalendarApp.newRecurrence().addYearlyRule();
Logger.log("accessing calendar");
var externalCalendar = CalendarApp.getCalendarById(calendarId);
externalCalendar.createAllDayEventSeries(title, start, recurrence, {
description : desc,
location : loc
});
}
function getRelativeDate(daysOffset, hour) {
var date = new Date();
date.setDate(date.getDate() + daysOffset);
date.setHours(hour);
date.setMinutes(0);
date.setSeconds(0);
date.setMilliseconds(0);
return date;
}
function CreateCalendarEvent(e) {
try {
Logger.log("creating event");
createEvent();
} catch (e) {
Logger.log(e.toString());
}
}
This sets a trigger function when the form is submitted, make sure that you change the value of the calendar id to the one provided by your calendar.