A question I've seen a few times on the major coding support fora, how to add an event to a calendar based on a form submit. Nevertheless, I'm struggling.
Timestamp form
Date
name
startTime
endTime
descr
25/05/2021 13:05:05
=to_date(A2)
Meeting
15:05:00
15:42:00
garden
The event would always take place on the date of the form submit. Nothing seems to come of the following code.
var spreadsheet = SpreadsheetApp.getActive().getSheetByName("Form1");
var data = spreadsheet.getRange("A2:F").getValues();
function toCal() {
let [, date, name, startTime, endTime, descr] = data;
var calen = CalendarApp.getCalendarById("examplecal#group.calendar.google.com");
calen.createEvent(name,
new Date(date + startTime),
new Date(date + endTime),
{location: "Brandenburger Tor", description: descr});
}
}
The event just needs to be based on the last submission, so I can put it on a "on form submit" trigger.
I think the trouble comes from the date time. However if I just put in new Date("25/05/2021 15:05:00") instead of a the current thing, nothing appears in my calendar as well.
Any help would be appreciated.
Format B2 to 2021-05-25
and try:
function toCal() {
var spreadsheet = SpreadsheetApp.getActive().getSheetByName("Form1");
var data = spreadsheet.getRange("A2:F2").getDisplayValues();
start = new Date(data[0][1] + " " + data[0][3]);
end = new Date(data[0][1] + " " + data[0][4]);
var calen = CalendarApp.getCalendarById("examplecal#group.calendar.google.com");
calen.createEvent(data[0][2], start, end,
{location: "Brandenburger Tor", description: data[0][5]});
}
I am new to writing scripts and I was experimenting.
I want to add time stamp along with the string.
const sheet = SpreadsheetApp.openByUrl(SHEET_URL).getSheetByName(
SHEET_NAME
);
const [header] = sheet.getRange('A1:1').getValues();
const STATUS = header.indexOf('Status');
var rowId = Number(e.parameter.row);
var date = new Date()
sheet.getRange(rowId + 1, STATUS + 1).setValue("Data Sent- " + date);
however, all I am getting the Status Column is Data Sent- and no time stamp.
please help where am i going wrong.
Thanks in advance.
You should convert the date to a string first, like this:
var date = new Date();
var timezone = 'GMC';
var format= 'YYYY-mm-dd';
var formatted_date = Utilities.formatDate(date,timezone , format);
sheet.getRange(rowId + 1, STATUS + 1).setValue("Data Sent- " + formatted_date);
Reference: GAS Utilities Format Date
I'm trying to create a Google Chart to Google Apps Script using a formula that already exists.
this formula works fine in the spreadsheet:
=query(A:A; "select A where A >= datetime '"&TEXT(today();"yyyy-MM-dd HH:mm:ss")&"'";-1)
this code doesn't work to Google Apps Script as intended:
query.setQuery("select A, B Where A >= toDate( now() )");
var query = new
google.visualization.Query('https://docs.google.com/spreadsheets/d/key');
query.setQuery("select A, B Where A = date '" + nowone + "'");
var nowone = getNowDate();
query.send(handleQueryResponse);
}
function getNowDate(){
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var date = date.getDate();
if (month < 10) {
month = "0" + month;
}
if (date < 10) {
date = "0" + date;
}
var strDate = String(year + "-" + month + "-" + date + " 00:00:00");
return strDate;
}
I've tried many times without success to replicate the formula to Google Apps Script.
thanks in advance...
I tried the query in the Spreadsheet and was able to get the expected results.
When coming to your code there are two things to be changed.
First one is you are calling the nowone variable before it is set to some value. For that you can just add that statement before the set query.
The second thing I found is that I instead of date in the query you should give datetime.
Please find the below code for reference:
function drawDashboard() {
var query = new google.visualization.Query(
'https://docs.google.com/spreadsheets/d/key/edit#gid=0');
var nowone = getNowDate();
//alert(nowone);
//query.setQuery("select A, B Where A >= toDate( now() )");
query.setQuery("select A,B where A >= datetime '"+nowone+"'");
query.send(handleQueryResponse);
}
In order to set the query using visualization class, you have to
1. Add this code in html file in apps script console.
2. create HTML output from file.
3. Then Deploy this as a webapp.
Tried this code below to get the data from query:
index.html:
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
var data ;
// Load the Visualization API and the controls package.
google.load('visualization', '1.0', {'packages':['controls']});
// Set a callback to run when the Google Visualization API is loaded.
google.setOnLoadCallback(drawDashboard);
// Callback that creates and populates a data table,
// passes in the data and draws it.
function drawDashboard() {
var query = new google.visualization.Query(
'https://docs.google.com/spreadsheets/d/key/edit#gid=0');
var nowone = getNowDate();
//alert(nowone);
//query.setQuery("select A, B Where A >= toDate( now() )");
query.setQuery("select A,B where A >= datetime '"+nowone+"'");
query.send(handleQueryResponse);
}
function getNowDate(){
var date = new Date();
var year = date.getFullYear();
var month = date.getMonth() + 1;
var date = date.getDate();
if (month < 10) {
month = "0" + month;
}
if (date < 10) {
date = "0" + date;
}
var strDate = String(year + "-" + month + "-" + date + " 00:00:00");
return strDate;
}
function handleQueryResponse(response) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
data = response.getDataTable();
// Create a dashboard.
alert(data);
}
</script>
</head>
code.gs:
function doGet() {
var html = HtmlService.createHtmlOutputFromFile('index');
html.setSandboxMode(HtmlService.SandboxMode.IFRAME);
return html;
}
When I access the webapp, I was able to see that the response is returning some object. In the handleQueryResponse(response) function you could add some more code to create a chart or a table for the returned data.
You can refer to this documentation for creating table for the data values. Hope that helps!
I've been using a script to pull data from a Google Spreadsheet and use that info to populate a Google Calendar. It works for the most part, but is very unstable: sometimes it does not work, and most times it generates an error, even if it does work.
One error I get a lot is "Cannot find method createAllDayEvent(string,number,object). (line 39, file "")", which, of course, does not make much sense, as that is a known valid method.
Below is my code: I would be super grateful to anyone who can help me tweak it to be a bit more reliable:
Thanks,
Sterling
function SpreadsheetToCalendar()
{
// This function should be executed from the spreadsheet you want to export to the calendar
var mySpreadsheet = SpreadsheetApp.getActiveSheet();
// These 2 methods do the same thing. Using the 2nd one, as 1st is deprecated
// var myCalendar = CalendarApp.openByName("Autodesk Renewals");
var myCalendar = CalendarApp.getCalendarById("rfx.com_bp79fdqvbortgmv21bj8am4hjc#group.calendar.google.com");
// optional - delete existing events
var events = myCalendar.getEvents(new Date("January 1, 2013 PST"),
new Date("December 31, 2016 PST"));
for (var i = 0; i < events.length; i++)
{
events[i].deleteEvent();
Utilities.sleep(300); // pause in the loop for 300 milliseconds
}
var dataRange = mySpreadsheet.getRange("A2:H300");
var data = dataRange.getValues();
// process the data
for (i in data)
{
var row = data[i];
// assume that each row contains a date entry and a text entry
var theContract = row[0] ;
var theDate = row[2] ;
var theCustomer = row[3] ;
var theAssign = row[5] ;
var theStatus = row[6] ;
var theNotes = row[7] ;
//var theTitle = (theCustomer + " | " + theContract + " | " + theAssign + " | " + theStatus);
var theTitle = ("| " + theCustomer + " | " + theContract + " | " + theAssign + " | " + theStatus + " |");
//myCalendar.createAllDayEvent(theTitle, theDate);
// myCalendar.createAllDayEvent(theTitle, new Date(date));
myCalendar.createAllDayEvent(theTitle, theDate, {description:theNotes});
Utilities.sleep(300); // pause in the loop for 300 milliseconds
}
}
as for the specific error regarding createAllDayEvent, note that each parameter has a type. your code is not validating that the cell from row[2] has a valid date and instead its passing a number, which is not expected.
you are also doing a for..in.. on an array which is bad (google it. tldr you will loop on the "count" property too.)
I want to use the calendar timezone to set the time zone of a date object. I'm looking for the proper technique. We have several bases around the nation, and each has their own calendar for journal and daily activities. We have multiple scripts that post to the calendars. I want to use the timezone of the calendar to set the date Object timezone, because the users travel around to different bases, and their computers might not be set to the correct time zone. We want to avoid incorrect time settings.
Should the script's timeZone be set to UTC?
This is where I'm currently at:
function submitUiTest(e) {
var app = UiApp.getActiveApplication();
var cal = CalendarApp.getCalendarById('calendarId');
var timeZone = cal.getTimeZone();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startTime = e.parameter.startDate
startTime.setHours(e.parameter.startHour, e.parameter.startMin, 0)
startTime = formatTime(startTime, timeZone);
Logger.log(startTime)
var endTime = e.parameter.endDate
endTime.setHours(e.parameter.endHour, e.parameter.endMin, 0);
endTime = formatTime(endTime, timeZone);
Logger.log(endTime)
cal.createEvent('TimeZone Test', new Date(startTime), new Date(endTime));
ss.appendRow([startTime, endTime]);
return app;
}
function formatTime(time, timeZone){
return Utilities.formatDate(time, (timeZone-time.getTimezoneOffset()), 'M/d/yyyy HH:mm');
}
Edit:
Currently there are 3 calendars, they are not user calendars, just each a separate calendar created for individual Air Stations. The air stations are each in separate time zone's. As crew members work at these stations they post daily activities to the calendars, and there are also several Ui scripts we have that post to the same calendars ex. a flight log. When an entry to a calendar is posted to any calendar, the time relates only to the timezone set on the script, not the timezone on the calendar. When the date or timestamp object is created, how can I use the timeZone that the calendar itself is set to.
What is best practice for scripts that record dates for different time zones?
Set the script timezone to UTC and do the conversion?
What do you use to get the user's timezone or in this case, I don't care what the user's timezone is set too, I need to use the timezone of the calendar.
Here is a modified version of the answer, without the UI stuff:
function gasTimezoneOffset(date, hour){
var cal,calTimeZone,calTz,date,dateString,scriptTimeZone,sessionTz;
var testMonth = "March",
testDayOfMnth = "26",
testYr = "2016",
hour = "10:00",
timeZoneDiff = 0;
Logger.log("Script Time Zone: " + Session.getScriptTimeZone());
dateString = testMonth + " " + testDayOfMnth + ", " + testYr;
Logger.log("dateString: " + dateString);
date = new Date(dateString);
cal = CalendarApp.getDefaultCalendar();
calTimeZone = cal.getTimeZone();
calTimeZone = Utilities.formatDate(date, calTimeZone, 'Z');
scriptTimeZone = Utilities.formatDate(date, Session.getTimeZone(), 'Z');
calTz = Number(calTimeZone.slice(0,3));
sessionTz = Number(scriptTimeZone.slice(0,3));
//If both time zones are the same sign, get the difference between the
//two. E.g. -4 and -2. Difference is 2
//if each time zone is a different sign, add the absolute values together.
//-4 and +1 should be 5
if (calTz < 0 && sessionTz > 0 || calTz > 0 && sessionTz < 0){
timeZoneDiff = Math.abs(Math.abs(calTz) + Math.abs(sessionTz));
} else {
timeZoneDiff = Math.abs(Math.abs(calTz) - Math.abs(sessionTz));
};
hour = Number(hour.slice(0,2));
return hour + timeZoneDiff;
};
EDIT : I wrote a small test UI and ran it with 2 calendars in 2 different timezones.
Calendar events are created in the Calendar timezone and the user interface shows user values. Google takes care of timezone settings in both calendars and I didn't notice any anomalies : events where created as I wanted to, ie at the time shown in the UI in the calendar Timezone.
(screen capture)
Here is the code I used for testing :
var tz = [['test_agenda(pacific Time)','test_agenda'],['testencodage(Belgium time)','testencodage']]
function doGet() {
var app = UiApp.createApplication().setStyleAttribute('padding','15PX');
var hpanel = app.createHorizontalPanel();
var dateBox = app.createDateBox().setId('dateBox').setName('dateBox');
var hour = app.createListBox(false).setId('hour').setName('hour')
for(h=0;h<25;++h){
if(h/2==parseInt(h/2)){hour.addItem(parseInt(h/2)+':00')
}else{
hour.addItem(parseInt(h/2)+':30')
}
}
var amPm = app.createListBox(false).setId('am').setName('amPm')
.addItem('AM').addItem('PM');
var dateTimeLabel = app.createLabel('',false).setId('dateTimeLabel');
var submit = app.createButton('Submit').setId('submit');
var tzList = app.createListBox().setName('tzList');
for(var c in tz){tzList.addItem(tz[c][0],tz[c][1])}
var handler1 = app.createClientHandler().validateMatches(dateBox, '2','g').forEventSource().setEnabled(false);
var handler2 = app.createServerHandler('createE').validateMatches(dateBox, '2','g').addCallbackElement(hpanel).addCallbackElement(tzList);
submit.addClickHandler(handler1).addClickHandler(handler2);
hpanel.add(dateBox).add(hour).add(amPm)
app.add(hpanel);
app.add(tzList).add(submit);
app.add(dateTimeLabel);
return app;
}
function createE(e) {
var app = UiApp.getActiveApplication();
var date = e.parameter.dateBox;
var cal = CalendarApp.getCalendarsByName(e.parameter.tzList)[0]
var timeZone = cal.getTimeZone();
var sessionTz = Session.getTimeZone()
Logger.log(sessionTz)
Logger.log(timeZone)
var hour = Number(e.parameter.hour.split(':')[0]);
var min = Number(e.parameter.hour.split(':')[1]);
var amPm = e.parameter.amPm;
if (amPm == 'PM' ){hour = hour+12}; // ADD 12 HOURS TO PM HOURS, EXCEPT 12PM
if (hour == 24){hour = 0;amPm='AM'}; // HANDLE 12AM HOUR CORRECTLY
var newDate=new Date(date)
newDate.setHours(hour,min,0,0)
Logger.log('start : '+newDate)
var newDateString = Utilities.formatDate(newDate, sessionTz, 'MM/dd/yyyy hh:mm aaa');
app.getElementById('dateTimeLabel').setText('tz = '+timeZone+' - '+newDateString);
Logger.log('end : '+new Date(newDate.getTime()+3600000))
cal.createEvent('test Event in TZ '+timeZone, newDate, new Date(newDate.getTime()+3600000))
app.getElementById('submit').setEnabled(true);
return app;
}
first comment :
I began to write a comment to ask you some questions but it was getting too long... so please consider this as a comment, not an answer ;-).
I'm not sure I understand what you say about 'their computer not being set to the right timezone' the timezone of their computer is not relevant if they use Google Calendar, it is only a matter of parameter in Google Cal. If I understood your goal is that if the script sets an appointment at 8:00 AM they will see it shown at 8:00 AM in their Calendar wherever they are (8:00 AM in their 'local' timezone), right ?
So to summarize, you are running this script from one place and creating events for people in other timezones in their own calendars ? And are the users moving across different timezones ? These are 2 separate questions and it doesn't have one single solution.
If a single user is moving across timezones all the events will be shifted unless he doesn't change his GCal parameters. But if he does so he won't be notified at the right time and the Calendar interface will be out of time... so that's not a reasonable solution.
My last question : when you create an event in another calendar (in another tz) can it be an appointment between you and this person ? in other words is the absolute time of any importance for you use case ?
Ok here is a solution to the problem. I've probably went way out of my way or missed something simple but this finally works like I was hoping. Feel free to critique. I set the webapp timezone to GMT-0000 just for simplicity.
function uiTest() {
var app = UiApp.createApplication();
var startDate = app.createDateBox().setName('startDate').setId('startDate').setWidth('75');
var startHour = app.createListBox().setName('startHour').setId('startHour').setWidth('45');
var startMin = app.createListBox().setName('startMin').setId('startMin').setWidth('45');
var endDate = app.createDateBox().setName('endDate').setId('endDate').setWidth('75');
var endHour = app.createListBox().setName('endHour').setId('endHour').setWidth('45');
var endMin = app.createListBox().setName('endMin').setId('endMin').setWidth('45');
for (h=0;h<24;++h){
if(h<10){
var hourstr='0'+h
}else{
var hourstr=h.toString()
}
startHour.addItem(hourstr)
endHour.addItem(hourstr)
}
for (m=0;m<60;++m){
if(m<10){
var minstr='0'+m
}else{
var minstr=m.toString()
}
startMin.addItem(minstr)
endMin.addItem(minstr)
}
var grid = app.createFlexTable().setId('grid');
app.add(grid);
grid.setWidget(0, 0, app.createLabel('Start Date'));
grid.setWidget(1, 0, startDate);
grid.setWidget(0, 1, app.createLabel('Hour'));
grid.setWidget(1, 1, startHour);
grid.setWidget(0, 2, app.createLabel('Min'));
grid.setWidget(1, 2, startMin);
grid.setWidget(2, 0, app.createLabel('End Date'));
grid.setWidget(3, 0, endDate);
grid.setWidget(2, 1, app.createLabel('Hour'));
grid.setWidget(3, 1, endHour);
grid.setWidget(2, 2, app.createLabel('Min'));
grid.setWidget(3, 2, endMin);
app.add(app.createButton('Submit', app.createServerHandler('submitUiTest').addCallbackElement(grid)));
SpreadsheetApp.getActiveSpreadsheet().show(app);
}
function submitUiTest(e) {
var app = UiApp.getActiveApplication();
var cal = CalendarApp.getCalendarById('');//Info Sys Calendar set to Central Time
//var cal = CalendarApp.getCalendarById('');//Fort Bliss (Mountain Time)
var calTimeZone = cal.getTimeZone();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var startTime = e.parameter.startDate
startTime.setHours(gasTimezoneOffset(startTime, e.parameter.startHour, calTimeZone), e.parameter.startMin, 0);
Logger.log('startTime: '+Utilities.formatDate(startTime, calTimeZone, 'M/d/yyyy HH:mm z'));
var endTime = e.parameter.endDate
endTime.setHours(gasTimezoneOffset(endTime, e.parameter.endHour, calTimeZone), e.parameter.endMin, 0);
Logger.log('endTime: '+endTime)
var timeStamp = Utilities.formatDate(startTime, calTimeZone, 'M/d/yyyy HH:mm z');
cal.createEvent(timeStamp, new Date(startTime), new Date(endTime));
ss.appendRow([startTime, endTime]);
return app;
}
function gasTimezoneOffset(date, hour, calTimeZone){
var calTz = new Number(Utilities.formatDate(date, calTimeZone, 'Z').substr(1,2));
var sessionTz = new Number(Utilities.formatDate(date, Session.getTimeZone(), 'Z').substr(1,2));
switch (Utilities.formatDate(date, calTimeZone, 'Z').substring(0,1)){
case '+':
var timeZoneOffset = sessionTz - calTz;
break;
case '-':
var timeZoneOffset = sessionTz + calTz;
break;
}
hour = new Number(hour);
return hour + timeZoneOffset;
}
Here's the version of Sandy's code that I ended up using to create a function that takes the Calendar object and the "script time" and returns the "calendar time":
/**
* Given a script date object, return the time in the user's calendar
*
* Sandy Good's answer to this SO question:
*
* http://stackoverflow.com/questions/15645343/how-to-use-timezone-of-calendar-to-set-timezone-for-date-object
*
* #param {Date} scriptDateTime
* #param {Calendar} calendar
*
* #return {Date} calendarDateTime
*/
function getCalendarDateTime (scriptDateTime, calendar) {
Logger.log('scriptDateTime: ' + scriptDateTime)
var calendarTimeZoneString = calendar.getTimeZone()
var calendarTimeZone = Utilities.formatDate(scriptDateTime, calendarTimeZoneString, 'Z')
var calendarTz = Number(calendarTimeZone.slice(0,3))
Logger.log('calendarTimeZone: %s (%s)', calendarTimeZoneString, calendarTz)
var scriptTimeZoneString = Session.getScriptTimeZone()
var scriptTimeZone = Utilities.formatDate(scriptDateTime, scriptTimeZoneString, 'Z')
var sessionTz = Number(scriptTimeZone.slice(0,3))
Logger.log('scriptTimeZone: %s (%s)', scriptTimeZoneString, sessionTz)
// If both time zones are the same sign, get the difference between the
// two. E.g. -4 and -2. Difference is 2
//
// If each time zone is a different sign, add the absolute values together.
// -4 and +1 should be 5
var timeZoneDiff
if (calendarTz < 0 && sessionTz > 0 || calendarTz > 0 && sessionTz < 0) {
timeZoneDiff = Math.abs(Math.abs(calendarTz) + Math.abs(sessionTz))
} else {
timeZoneDiff = Math.abs(Math.abs(calendarTz) - Math.abs(sessionTz))
}
Logger.log('timeZoneDiff: ' + timeZoneDiff)
var scriptHour = scriptDateTime.getHours()
var calendarHour = scriptHour + timeZoneDiff
var calendarDateTime = new Date(
scriptDateTime.getYear(),
scriptDateTime.getMonth(),
scriptDateTime.getDate(),
calendarHour,
scriptDateTime.getMinutes())
Logger.log('calendarDateTime: ' + calendarDateTime)
return calendarDateTime
}
// Script is PST (GMT-8) and calendar is GMT
function test_getCalendarDateTime() {
var calendar = CalendarApp.getDefaultCalendar()
var scriptDateTime = new Date(2017, 0, 30, 12, 0) // 2017-01-30 12:00 PST
var calendarDateTime = getCalendarDateTime(scriptDateTime, calendar) // 2017-01-30 20:00 PST
}
Could try deploying a separate web app for each time zone. Set the time zone of each app to match that of the unique calendar they are linked to. Since you only have 3 calendars in different time zones, seems like it would work for your case.