Can anyone assist in why I'm getting a "NaN" for dates in the code below? I'm trying to create a calendar event but it keeps giving indicating "NaN" in the Logger.log. Execution transcript shows the following;
"Execution failed: Cannot find method createEvent(string,number,number). (line 38, file "Code")"
This is part of the code. The script runs based on a form submit of two dates. The script grabs the values from a spreadsheet. For example the two dates could be 4/1/2014 and 4/2/2014.
Here is the code:
var ptoCalendar = CalendarApp.getCalendarById("ENTER CALENDAR ID")
var startDate = Utilities.formatDate(new Date(sheet.getRange(i,j-3,1,1).getValue()), 'GMT', "yyyy-MM-dd'T'HH:mm:ss");
var cnvtStartDate = new Date(startDate).setHours(08,00,00);
Logger.log(cnvtStartDate);
var endDate = Utilities.formatDate(new Date(sheet.getRange(i,j-2,1,1).getValue()), 'GMT', "yyyy-MM-dd'T'HH:mm:ss");
var cnvtEndDate = new Date(endDate).setHours(17,00,00);
Logger.log(cnvtEndDate);
var createEvent = ptoCalendar.createEvent(recipientName+'- PTO', cnvtStartDate, cnvtEndDate);
Any assistance is appreciated..
UPDATED CODE PRIOR TO Serge Response - My solution at the moment. NOTE: I'm providing the full function here, were as before was just a snippet
//This takes the date string from managersDecission() and covnerts back to a date type
function parseDate(dateString){
var time = Date.parse(dateString);
if(!time){
time = Date.parse(dateString.replace("'T'"," "));
if(!time){
bound = dateString.indexOf('T');
var dateData = dateString.slice(0, bound).split('-');
var timeData = dateString.slice(bound+1, -1).split(':');
time = Date.UTC(dateData[0],dateData[1]-1,dateData[2],timeData[0],timeData[1],timeData[2]);
}
}
return new Date(time);
}
//Used to update the employee requested PTO in the request spreadsheet with managers decision
function managersDecission() {
//Section get the tracking spreadsheet and its values & requests the decision made by manager in grabRequestID()
var ss = SpreadsheetApp.openById(trackingSS)
var sheet = ss.getSheetByName('Requests');
var data = sheet.getDataRange().getValues();
var decision = grabRequestID();
//for loop to set the decision of the manager for tracking
for (var i=0; i < data.length; i++) {
for (var j=0; j < data[i].length; j++) {
if (data[i][j] == decision[0] && decision[1] == "Approved") {
sheet.getRange(i+1,j+3,1,1).setValue(decision[1]);
var recipientEmail = sheet.getRange(i+1,j,1,1).getValue();
var recipientName = sheet.getRange(i+1,j-1,1,1).getValue();
//This section creates the calendar event for approved PTO
var ptoCalendar = CalendarApp.getCalendarById('CALENDAR ID')
var startDate = Utilities.formatDate(new Date(sheet.getRange(i+1,j-3,1,1).getValue()), 'GMT', "yyyy-MM-dd'T'HH:MM:SS");
//Debug Line
//Logger.log("start date is "+startDate)
var cnvtStartDate = parseDate(startDate);
//Debug Line
//Logger.log("parsed start date "+cnvtStartDate);
var setHourStartDate = cnvtStartDate.setHours(08,00,00,00);
//Debug Line
//Logger.log("start Hours set "+setHourStartDate);
var endDate = Utilities.formatDate(new Date(sheet.getRange(i+1,j-2,1,1).getValue()), 'GMT', "yyyy-MM-dd'T'HH:MM:SS");
//Debug Line
//Logger.log("end date is "+endDate);
var cnvtEndDate = parseDate(endDate);
//Debug Line
//Logger.log("parse end date "+cnvtEndDate);
var setHourEndDate = cnvtEndDate.setHours(15,00,00,00);
//Debug Line
//Logger.log("end Hours set "+setHourEndDate);
var createEvent = ptoCalendar.createEvent(recipientName+'- PTO', cnvtStartDate, cnvtEndDate);
ADDING LOG INFO FOR SERGE'S BELOW COMMENT
[14-03-20 16:08:05:541 PDT] start date is 2014-03-31T07:03:00
[14-03-20 16:08:05:545 PDT] parsed start date Mon Mar 31 2014 00:03:00 GMT-0700 (PDT)
[14-03-20 16:08:05:545 PDT] start Hours set 1396278000000
[14-03-20 16:08:05:546 PDT] end date is 2014-04-02T07:04:00
[14-03-20 16:08:05:547 PDT] parse end date Wed Apr 02 2014 00:04:00 GMT-0700 (PDT)
[14-03-20 16:08:05:547 PDT] end Hours set 1396476000000
UPDATED DID SOME TESTING BASED ON Serge comment indicating cnvtStartDate was a date object
I removed the Utilities.formatDate and in fact the value pulled from spreadsheet is a date value and will allow script to run successfully. Issue was that is creates the calendar event for 12:00AM. Since this should block a full work day out (PTO day), I need it to set some times for start /end.
When running the script now and using the following:
var startDate =new Date(sheet.getRange(i+1,j-3,1,1).getValue());
var setHourStartDate = startDate.setHours(08,00,00,00);
var endDate = new Date(sheet.getRange(i+1,j-2,1,1).getValue());
var setHourEndDate = cnvtEndDate.setHours(15,00,00,00);
var createEvent = ptoCalendar.createEvent(recipientName+'- PTO', setHourStartDate, setHourEndDate);
The following error is giving. It thinks the ssetHourStartDate and end is a number??
"Execution failed: Cannot find method createEvent(string,number,number)."
I then adjusted he code to the following:
var startDate =new Date(sheet.getRange(i+1,j-3,1,1).getValue());
var setHourStartDate = new Date(startDate.setHours(08,00,00,00));
var endDate = new Date(sheet.getRange(i+1,j-2,1,1).getValue());
var setHourEndDate = new Date(endDate.setHours(17,00,00,00));
var createEvent = ptoCalendar.createEvent(recipientName+'- PTO', setHourStartDate, setHourEndDate);
And all is working well. It will create single day event for the full day or span multiple days across the top of calendar.
Thanks Serge as always for pointing thing out ..
why do you use Utilities.formatDate in the first place ?
If the cell in the sheet is a date you don't need to convert it to a string, just use it as it is.
If you really want to use it that way then use the correct syntax like below :
var cnvtStartDate = new Date("2014/03/20"):// I replaced with the string "as it should be"
cnvtStartDate.setHours(8,0,0,0);
Logger.log(cnvtStartDate);// this is a date object
Related
Thanks in advance to anyone who can help with my issue. I'm not a professionnal I just code when I don't want to do a task anymore.
So I'm running a script to send automaticaly emails 3 days after I see a client. Two days ago, I see that my emails are not been sent at the correct date. So I enter different date to see what's the problem is and the code just send reply for any given date in my google sheet. All date but the 31/05/2022 for some reason.
So I just waited a couple of days to fix it and when I came back the code just stop working completely. Meaning it doesn't send any email anymore.
I'm using the following code with a time trigger and I dont see why it doesnt work anymore.
function MailingAutoJuillet() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Juillet");
var startRow = 3;
var numRows = sheet.getLastRow()-1;
var dataRange = sheet.getRange(startRow, 1, numRows, sheet.getLastColumn());
var data = dataRange.getValues();
var EMAIL_SENT = 'EMAIL_SENT';
var NO_EMAIL = 'NO_EMAIL';
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var date = new Date();
var sheetDate = new Date(row[2]);
Sdate = Utilities.formatDate(date,'Europe/Paris','EEE, MMM d, yyyy')
SsheetDate = Utilities.formatDate(sheetDate,'Europe/Paris','EEE, MMM d, yyyy')
if (Sdate >= SsheetDate+3){
if (row[13] != EMAIL_SENT)
if (row[13] != NO_EMAIL) {
const HTMLTemplate = HtmlService.createTemplateFromFile("HTML Mail de rappel")
const HTMLforemail = HTMLTemplate.evaluate().getContent()
var emailAddress = row[9];
var emailText = "Text";
var subject = "Text";
var option={
htmlBody:HTMLforemail
};
GmailApp.sendEmail(emailAddress,subject,emailText,option);
sheet.getRange(startRow+i,14).setValue("EMAIL_SENT");
}
}
}
}
Attempting to use greater than operator to compare strings
You cannot compare dates in this manner
Sdate = Utilities.formatDate(date,'Europe/Paris','EEE, MMM d, yyyy')
SsheetDate = Utilities.formatDate(sheetDate,'Europe/Paris','EEE, MMM d, yyyy')
The above are strings and cannot be compared with greater than operators
if (Sdate >= SsheetDate+3){
Take a look at the getTime() or valueOf() methods that return milliseconds which can be compared in the manner that you wish.
use the function Logger.log() to know what exactly you code are doing.
Since you don't have any clue I would recommend starting knowing the values of each variable:
Logger.log("varname=",varname);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Juillet");
ex: Logger.log("sheet=",sheet);
Also, I don't know how exactly is your sheet, but let my try to understand what is happening here:
var sheetDate = new Date(row[2]); //row is expected to be an array
but
var row = data[i]; so... row receive here the values in data? It's data an 2d array?
Also, check your executions. It's the fourth icon on the left panel in the new IDE
You can't compare dates that way.
SsheetDate = Utilities.formatDate(sheetDate,'Europe/Paris','EEE, MMM d, yyyy')
...is going to produce a string value, like "Tue, Jun 7, 2022". You can't add the number three to that to get a date three days later. All you'll be doing is comparing something like "Tue, Jun 7, 2022" to "Tue, Jun 7, 20223", and they will compare as strings, not as dates or numbers.
A day is 86,400,000 milliseconds. When Sdate is three or more days after SsheetDate, Sdate.getTime() > SsheetDate.getTime() + 259200000.
There are more elegant, easier-to-read ways to compare dates, but those methods are more complicated and/or depend on particular date/time libraries.
Firstly, I have a var that contains a date (just one for the moment):
var disableddates = ["26-05-2018"];
Now I want to check if this date is in a certain date range. The starting date and ending date are coming form a datepicker (with jQuery calendar plugin). These dates are processed like this:
Arrival date:
//Get arrival date from datepicker
function aankomstdatumInput() {
aankomstDatum = document.getElementById("aankomstdatum").value;
document.getElementById("aankomst").innerHTML = aankomstDatum;
var parts = aankomstDatum.split('-');
aankomstDatumDate = new Date(parts[2],parts2[1]-1,parts2[0]);
}
Departure date:
//Get departure date from datepicker
function vertrekdatumInput() {
vertrekDatum = document.getElementById("vertrekdatum").value;
document.getElementById("vertrek").innerHTML = vertrekDatum;
var parts2 = vertrekDatum.split('-');
vertrekDatumDate = new Date(parts2[2],parts2[1]-1,parts2[0]);
}
Now I need a function that checks every date in the disableddates array if it's in the range of aankomstDatumDate and vertrekDatumDate.
Since these two dates are formulated in the following way: Sat May 05 2018 00:00:00 GMT+0200 (Romance Daylight Time), I first have to set the disabled date in the same formulation, so I started the function like this:
function checkDisabledDate{
var parts3 = disableddates.split('-');
disabledDatumDate = new Date(parts3[2],parts3[1]-1,parts3[0]);
}
I think that's a good first step, but then I'm stuck at how I can check if disabledDatumDate is between aankomstDatumDate and vertrekDatumDate and then start and else/if depending if the disabled date is in between the arrival date and departure date or not.
function checkDisabledDate{
for(var i = 0; i < disableddates.length; i++){
var parts3 = disableddates.split('-');
disabledDatumDate = new Date(parts3[2],parts3[1]-1,parts3[0]);
var diff1 = vertrekDatumDate - disabledDatumDate;
var diff2 = vertrekDatumDate - aankomstDatumDate;
if(diff2 > diff1){
//disabledDatumDate within date range
//do something
}
}
}
I am using Google Apps Script with a Google form. When the user submits the Google Form I get a value from a question. I then take that value and make it a date object, from what I saw on this post about daylight savings I use that to determine the timezone. I run the date object through Utilities.formatDate and want to get the correctly formatted date.
example: 9:00 AM
But instead I am getting a completely different time than expected.
My question is: Can someone help me understand why the below code is outputting a time that is 3 hours different?
function onSubmit(e) {
var values = e.values;
Logger.log(values);
try {
var start1 = new Date(values[3]);
var startN = new Date(start1).toString().substr(25,6)+"00";
var startT = Utilities.formatDate(start1, startN, "h:mm a");
Logger.log(startT);
} catch(error) {
Logger.log(error);
}
}
The assumption that Utilities formatDate does not support GMT... parameter is not true.
The post you mentioned in reference is used to get calendar events and is a useful way to get the right value when you get events from another daylight saving period (getting the TZ info from the calendar event itself), for example events for next month will be in "summer time" while we are still in "winter time"...
Your issue might come from different sources depending on time zone settings of your script vs timezone of the source. Could you describe the exact configuration in which you use this script ?
In the mean time, here is a small code that demonstrates how the code is working + the logger results :
function testOnSubmit() {
var eventInfo = {};
var values = {};
values['3'] = new Date();
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n\n');
onSubmit(eventInfo);
}
function onSubmit(e) {
var values = e.values;
try {
var start1 = new Date(values[3]);
Logger.log('onSubmit log results : \n');
Logger.log('start1 = '+start1)
var startN = new Date(start1).toString().substr(25,6)+"00";
Logger.log('startN = '+startN);
var startT = Utilities.formatDate(start1, startN, "h:mm a");
Logger.log('result in timeZone = '+startT);
} catch(error) {
Logger.log(error);
}
}
EDIT : additionally, about the 30 and 45' offset, this can easily be solved by changing the substring length like this :
var startN = new Date(start1).toString().substr(25,8);
the result is the same, I had to use the other version a couple of years ago because Google changed the Utilities.formatDate method at some moment (issue 2204) but this has been fixed.
EDIT 2 : on the same subject, both methods actually return the same result, the GMT string has only the advantage that you don't have to know the exact timezone name... there is also the Session.getScriptTimeZone() method. Below is a demo script that shows the resulst for 2 dates in January and July along with the log results :
function testOnSubmit() {
var eventInfo = {};
var values = {};
values['3'] = new Date(2014,0,1,8,0,0,0);
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n\n');
onSubmit(eventInfo);
values['3'] = new Date(2014,6,1,8,0,0,0);
eventInfo['values'] = values;
Logger.log('eventInfo = '+JSON.stringify(eventInfo)+'\n');
onSubmit(eventInfo);
}
function onSubmit(e) {
var values = e.values;
var start1 = new Date(values[3]);
Logger.log('onSubmit log results : ');
Logger.log('start1 = '+start1)
var startN = new Date(start1).toString().substr(25,8);
Logger.log('startN = '+startN);
Logger.log('result in timeZone using GMT string = '+Utilities.formatDate(start1, startN, "MMM,d h:mm a"));
Logger.log('result in timeZone using Joda.org string = '+Utilities.formatDate(start1, 'Europe/Brussels', "MMM,d h:mm a"));
Logger.log('result in timeZone using Session.getScriptTimeZone() = '+Utilities.formatDate(start1, Session.getScriptTimeZone(), "MMM,d h:mm a")+'\n');
}
Note also that the Logger has its own way to show the date object value ! it uses ISO 8601 time format which is UTC value.
Try this instead:
var timeZone = Session.getScriptTimeZone();
var startT = Utilities.formatDate(start1, timeZone, "h:mm a");
The Utilities.formatDate function expects a time zone that is a valid IANA time zone (such as America/Los_Angeles), not a GMT offset like GMT+0700.
I am making the assumption that Session.getScriptTimeZone() returns the appropriate zone. If not, then you might need to hard-code a specific zone, or use a different function to determine it.
Additionally, the +"00" in the script you had was assuming that all time zones use whole-hour offsets. In reality, there are several that have 30-minute or 45-minute offsets.
I have a Google App Script that stopped working and throws the Error "TypeError: Cannot find function getHours in object 17.". Since we haven't made any changes in the code and I'm not too familiar with Google App Script/Javascript, I hope someone can point me to the right direction.
The code is much longer than this but I'm giving an example of an appearance of the getHours function (I can provide the full code if needed):
if (action.indexOf("[") == -1 && action != "") { // Check if there is some operation to take action
var roomtype = row[1]; // Reading data from the table
var desc = row[8];
var date = row[2];
var tstart = row[3];
var tstop = row[4];
var name = row[5];
var company = row[9];
var short_title = RoomShortcuts[0][roomtype] + " " + name + " (" + company + ")"; // Creating title of the Calendar entry
if (action == "Tentative") { short_title = "PROV: " + short_title; } // This is for Tentative events
var year = date.getYear(); // Getting the date and time and transforming it for the calendar
var month = date.getMonth();
var day = date.getDate();
var startHour = tstart.getHours();
var startMinute = tstart.getMinutes();
var stopHour = tstop.getHours();
var stopMinute = tstop.getMinutes();
var startdate = new Date(year, month, day, startHour, startMinute);
var stopdate = new Date(year, month, day, stopHour, stopMinute);
if (roomtype == "Gallery") {
var repeat = 2;
cal_EventCalendar[0]['Gallery'] = CalendarApp.openByName("Hub SMR");
} else {
var repeat = 1;
}
Thanks a lot!
I had a similar problem. I was able to use getHours in one script but got the same error when trying to access the sheet from another script. Anyhow, after reading:
http://www.w3schools.com/jsref/jsref_gethours.asp
I put together the following solution:
function weeklyUpdater() {
var sheet = SpreadsheetApp.getActiveSheet();
var schedule = sheet.getRange(2, 2, sheet.getLastRow() + 1, 3).getValues();
var hours = new Date(schedule[0][2]); // parse string into date
var hoursX = hours.getHours();
Logger.log(hoursX + ":");
}
The key is using new Date whereas in my other script schedule[0][2].getHours() works!
Anyhow, hope this helps.
I don't know what row is, or where it's defined. But the 4th element is a number object, with a value of 17, not whatever object you expected it to be.
var tstart = row[3];
var startHour = tstart.getHours(); // Number object has no function getHours()
the issue is in your spreadsheet, not in your script.
You can easily test that by double clicking on the cell that correspond to row[3] (most probably in column D) and see what happens : if it's a date object that shows only hours:minutes then it will give you a calendar popup like this:
If it is a 'ordinary' number or string then nothing special will happen and your script will never get any hour or minute from it since these statements need a date object as argument.
This is one of the dangers of spreadsheets that makes things look like what they are not, in this case showing time value in hours and minutes while the object behind is is a full date value with years, seconds and milliseconds... one often forget that ;-)
So, check the most recent cell values and I'm pretty sure you'll find that someone typed a value the wrong way and that the spreadsheed failed to translate it into a date value.
How do I handle dates from a spreadsheet like this.
I need to get the last date from column 2 and then find the next date. I have created this code for retrieving the last date.
lastDateRow = sheet.getLastRow()-1;
lastDate = Date(sheet.getRange("B"+(lastDateRow)+":B"+(lastDateRow).getValue());
The value you get from the sheet is already a date object (complete with year, date, hours etc), no further action should be necessary.
When you say 'next date' I guess you meant 'next day' ? If so, simply add 24*60*60*1000 to the date in milliseconds and you'll get the next day ;-)
In code it becomes something like this :
function xxx(){
var sheet = SpreadsheetApp.getActiveSheet()
var lastDateRow = sheet.getLastRow();
var lastDate = sheet.getRange(lastDateRow,2).getValue();
Logger.log(lastDate)
var nextDay = new Date(lastDate.getTime()+24*60*60*1000);
Logger.log(nextDay)
}
Logger result on a test :
Tue Aug 21 15:00:00 PDT 2012
Wed Aug 22 15:00:00 PDT 2012
Actualy this is what I ended up with after looking up js nextdate fnction here on stackowerflow.
var lastDateRow = sheet.getLastRow();
var lastDate = sheet.getRange(lastDateRow,2).getValue();
lastDate = getTomorrow(lastDate,1);
function getTomorrow(d,offset) {
if (!offset) { offset = 1 }
return new Date(new Date(d.getTime()).setDate(d.getDate() + offset));
}