add time from cells programmatically - javascript

I have a a spreadsheet which I use to note how I spent my time on a project. In that spreadsheet I have a couple of columns, one of which is the time spent doing something and the other is the category of what that something is (for example meetings or accounting or calling customers). I am trying to write a script which I pass the name of the category and it then loops though all the rows to see if the category equals the category I passed it, and if so it adds the time to the counter. I am however having trouble adding the time together. What I have so far is this:
function getTimeInCat(cat){
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var time = new Date();
var counter = 0;
for(var i = 6; i < numRows; i++){
var carCell = "F" + i;
var cellName = "E" + i;
if(sheet.getRange(i, 6).getValue() == cat){
time += sheet.getRange(i, 5).getValue();
counter++;
}
}
return time;
}
Instead of what I want I get this in return:
Thu Jan 30 2014 18:29:22 GMT-0000 (GMT)Sat Dec 30 1899 00:50:39 GMT-0000 (GMT)Sat Dec 30 1899 00:05:39 GMT-0000 (GMT)
EDIT: It is giving the right amount of rows (The remnants of that test are still in the code)

Try var time = 0. Date() I think will transform your time to a date.

The values of those cells are actually Date objects. This is why you're getting a long string of timestamps when you add the values of the cells together. For whatever reason, Google decided that when you're entering a duration, it will actually be an offset of HH:mm:ss after 12/30/1899. Try changing the format of those times to a date (Format > Number > Date) and you'll see it changes to that date.
Luckily, with Date objects, you can use the getTime() function to get your total duration. getTime() gives you the number of milliseconds since 1/1/1970 so it will actually return very large negative numbers for those cells but that's easy enough to manage. You just need to create a Date object with 12/30/1899 as the date and subtract that from the value of the cell you want.
var base = new Date("12/30/1899").getTime(); // -2.2091436E12
var cell = sheet.getRange(row,col).getValue().getTime(); // some other large negative number
var delta = cell - base; // this should be your duration in milliseconds

Related

My code just decided to stop working and I don't know why. (javascript google appscript)

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.

Add 1 day to date from spreadsheet via Google App Script / Javascript- Month Keeps Reseting to current month

I am trying to set up a Google App Script function that grabs a date (formatted dd/mm/yy) from the last column of a spread, and creates a new column with the date + one day.
I have seen previous solutions and tried to use the same, i.e.newDate.setDate(lastDate.getDate()+1) but have had issues getting the value formatted correctly in the script. This is a variation of my code that I'm using to loop through for a year's worth of values to see what I get:
for (var i=0;i<365;i++){
var lastRow = outputSheet.getLastRow();
var newDate = new Date();
var lastDate = outputSheet.getRange(lastRow,1).getValue();
var newDateRng = outputSheet.getRange(lastRow+1,1);
Logger.log(lastDate + 1, typeof lastDate, typeof (lastDate + 1));
newDate.setDate(lastDate.getDate());
Logger.log(newDate);
newDate.setDate((newDate.getDate() + 1));
Logger.log(newDate);
var newDateFormatted = Utilities.formatDate(newDate, ss.getSpreadsheetTimeZone(), "dd/MM/YY");
Logger.log(newDateFormatted);
newDateRng.setValue(newDateFormatted);
}
With a start date of "01/03/2020", I get the following behaviour:
01/03/2020
02/05/2020
03/05/2020
...
31/05/2020
01/06/2020
02/05/2020
03/05/2020
...
31/05/2020
01/06/2020
02/05/2020
...
etc. All the way through the year. Although the day increase, the month seems to reset after the first day of the month.
As a note, I am specifically looking to pick the date off of the spreadsheet rather than using new Date as today and new Date +1 as tomorrow.
Thanks
You need to use a different variable in the loop otherwise you will always return to the same month.
Also avoid using strings for the result, keep date objects and display it properly.
The code goes like this :
function otherTest(){
var lastDate = SpreadsheetApp.getActiveSheet().getActiveCell().getValue();
var date = new Date(lastDate); // create new date object
var result = [];
for (var i=0;i<365;i++){
date=new Date(date).setDate(new Date(date).getDate()+1)
Logger.log('date='+new Date(date))
result.push([new Date(date)]);
}
SpreadsheetApp.getActiveSheet().getRange(1,2,result.length,1).setValues(result).setNumberFormat('dd/MM/yyyy');
}

Google Script: getValue from row with today's date

I am working with google sheets scripting and am trying to identify values which exceed a certain threshold. In this case there are 3 variables f1,f2 and pf. When the cell with the highest value (out of the three) exceeds 500, it will write the value to another cell. The end game is to create an onEdit trigger that will be able to automatically check the values as they are entered daily and send email notifications if the limit is breached. But for simplicity I have missed this bit out for now. I am struggling to get the script to getValues() from the row that contains today's date.
Here is an example of the data
A B C D
____________________________________
1 | H2S values
2 | Date f1 f2 pf
3 |30/10/17 971.4 1037.6 809
4 |31/10/17 795.6 795.1 576
5 |01/11/17 429 444.3 351.8
Instead of taking the row with today's date, it takes the top row of the date range. The rest of the code works in terms of the limits and taking the highest value, but I can't figure out how to match the row with the date. 'Today_row' should return the row number which matches the date i.e on the 01/11/17 'Today_row' should equal 5, but instead it returns the first row in the 'daterange' and so it returns row 3.
Here is the code I am working on:
function readCell() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
// set today's date
var date = sheet.getRange("F1").setValue(new Date());
// look up date range
var daterange = sheet.getRange("A3:A");
// find the row position of today's date
if (date = daterange) {
var today_row = daterange.getRow();
var today_set = sheet.getRange("F2").setValue(today_row); }
// set today's variables and show value in cell
var today_h2s_f1 = sheet.getRange("B"+today_row).getValue();
var today_f1_set = sheet.getRange("F3").setValue(today_h2s_f1);
var today_h2s_f2 = sheet.getRange("C"+today_row).getValue();
var today_f2_set = sheet.getRange("F4").setValue(today_h2s_f2);
var today_h2s_pf = sheet.getRange("D"+today_row).getValue();
var today_pf_set = sheet.getRange("F5").setValue(today_h2s_pf);
// Set value of cell if the h2s level exceeds 500ppm, highest value out of f1,f2 and pf is chosen
if (today_h2s_f1 > 500 && today_h2s_f1 > today_h2s_f2 && today_h2s_f1>today_h2s_pf) {
var highest_h2s = sheet.getRange("F6").setValue(today_h2s_f1)}
else if (today_h2s_f2 > 500 && today_h2s_f2 > today_h2s_f1 && today_h2s_f2 >today_h2s_pf){
var highest_h2s = sheet.getRange("F6").setValue(today_h2s_f2)}
else if (today_h2s_pf > 500 && today_h2s_pf > today_h2s_f1 && today_h2s_pf >today_h2s_f2){
var highest_h2s = sheet.getRange("F6").setValue(today_h2s_pf)}
}
Any help will be much appreciated - thank you.
Getting daterange gives you a Range Object which you need to iterate in order to match a specific cell. First, we need to get a range of dates and then nullify timestamp information before comparing. Make the following changes:
// set and store a date object for today
var date = sheet.getRange("F1").setValue(new Date()).getValue();
// Get the range of dates to test
var daterange = sheet.getRange("A3:A").getValues()
// iterate the values in the range object
for(var i=0; i<daterange.length; i++) {
// Compare only month/day/year in the date objects
if(new Date(daterange[i]).setHours(0,0,0,0) == date.setHours(0,0,0,0)) {
// if there's a match, set the row
// i is 0 indexed, so add 3 to get the correct row
var today_row = (i+3);
// rest of your code
}
}
I haven't tested each of your variables set in the if block, but this bit returns a correct evaluation of the date as well as the correct row.

using the time as a dynamic variable to compare values

I am working on programming a page in JS that grabs calendar data from an outside source, imports it into a multidimensional array and uses it to display who is currently working along with their photo, phone number, etc.
Right now I have it set up so that the page reloads every 15 minutes. I'd prefer to have this all done dynamically so that when, say, the clock strikes 5pm the page knows to update without having to wait until the 15 minute refresh is triggered.
All of the work times are pulled from the other calendar in 24 hour format (so 5pm is 1700).
Here's how I'm generating the current time to compare with the start/end times in the calendar:
//Get the current date and time
var dateTime = new Date();
var month = dateTime.getMonth() + 1;
var day = dateTime.getDate();
var dayOfWeek = dateTime.getDay();
var year = dateTime.getYear() + 1900;
//converting hours and minutes to strings to form the 24h time
var hours = dateTime.getHours().toString();
if (hours.length === 1) {
var hours = '0' + hours
};
var minutes = dateTime.getMinutes().toString();
if (minutes.length === 1) {
var minutes = '0' + minutes
};
var time = hours + minutes;
//convert the 24h time into a number to read from later
var timeNumber = parseInt(time);
I then use if statements to compare the start/end times from the imported schedule with timeNumber to determine who is currently working and push that to an array that is eventually displayed on the page with this code:
//figure out who is currently working and put them in the workingNow array
var workingNow = [];
for (i = 0; i < workingToday.length; i++){
//convert time strings to numbers to compare
var startTime = parseInt(workingToday[i][7]);
var endTime = parseInt(workingToday[i][8]);
//compare start and end times with the current time and add those who are working to the new list
if(startTime < timeNumber && timeNumber < endTime){
workingNow.push(workingToday[i]);
}
};
I guess I have just been trying to figure out how to make this comparison of the data in an array with the current time something that is dynamic. Is this possible or would I need to go about this in a completely different way from the ground up?
You should have a look at momentjs. This is a really good library to handle all sort of time and date manipulation.
http://momentjs.com/

Javascript / Google Apps Script for loop find match but continue

I'm definitely not an expert and write in google apps script for simple workflows. One to help with repetitive tasks and two to continually try and learn programming..
I'm looking for assistant is how to approach the following setup. I'm not sure if thinking a "for" loop and maybe "if / else" is the way to approach.
I'll be reading data from a spreadsheet, specifically 4 rows, 4 columns. One of the columns will have dates. I'm comparing those dates to the current date to see if the date is 7 days prior. If so do something but then continue looking over the dates to see if another day is also within seven days and if so also do something.
For example:
dates: 2/4/2014, 2/28/2014, 2/11/2014, 2/25/2014
today's date: 3/1/2014
I want to loop over the dates, see that 2/28/2014 is within seven days of today's date and send an email, then continue checking the dates, and see that 2/25/2014 is also within seven days and send another email.
I'm not looking for the answer I'm looking on how to approach this,
my thought (rough)
for (i=0, i<dates.length; i++) {
if (dates[i] <= (different between today's date and dates[i]) {
send an email;
continue looping;
} else if {
continue;
}
}
hopefully kinda of get the point. :)
EDIT: UPDATE**
Here is what I've come up with so far... Below is the code and spreadsheet values for the dates.
Dates in spreadsheet C1:C4 (2/5/2014, 2/15/2014, 2/28/2014, 3/2/2014)
function calculateDays() {
//Gets the dates of schedule
var ss = SpreadsheetApp.getActiveSheet();
var dataRange = ss.getRange("C1:C4");
var values = dataRange.getValues();
//Caculation for single day
var one_day = (1000 * 60 * 60 * 24);
//For loop to get the values from spreadsheet
for (i = 0; i < values.length; i++) {
//Puts dataRange values into date format
var scheduledDays = new Date(values[i]);
var today = new Date();
//grabs times from today and scheduled days in millseconds and subtracts
var difference = scheduledDays.getTime() - today.getTime();
//divides to get number of dates, rounds, and converts to positive integer
var diffDay = Math.abs(Math.floor(difference / one_day));
Logger.log(diffDay);
}
What i'm unsure about next is how to loop over the variable diffDays to determine if the days is seven days prior to today's date. I know one is.. Could be i'm just tired but thoughts would be helpful.
I tried
for (j = 0; j < diffDays; j++) {
Logger.Log(diffDays[j]);
}
As a starting point to see what was logged but it showed blank... That's why i fell stuck.
UPDATED Based on Serge reply - New issue
Here is the updated code using Serge's suggested code. Adjusted a bit to help understand values that are being returned to me in the logger. Also adjust adding 7 days to today date to get future date for comparison. (see below code for additional comments)
function myFunction() {
var data = SpreadsheetApp.getActiveSheet().getRange("C1:C4").getValues();
var week = (1000*60*60*24*7);
Logger.log('a week is ' + week);
var todayDaysTime = new Date().setHours(0,0,0,0);
Logger.log('this is today= ' +todayDaysTime);
var weekPlusSevenDays = week + todayDaysTime;
Logger.log('this is todayDaysTime + a week ' +weekPlusSevenDays);
for (i=0 ; i<data.length; i++) {
Logger.log('Value of date in cell = '+data[i][0].getTime());
if (data[i][0].getTime() == weekPlusSevenDays) {
//send an email;
Logger.log('mail sent');
}
}
}
I've updated the dates in the spreadsheet column C to be 3/9/2014, 3/10/2014, 3/11/2014, and 3/12/2014. So what i would expect is that is the code would run, see that value 3/11/2014 in the spreadsheet is equal to todaysDaysTime + week. I'm trying to take todays date and add seven days to it and see if it matches a date in the spreadsheet. So far its not matching. Here is a copy of the logger.log.
[14-03-04 09:55:09:770 PST] a week is 604800000
[14-03-04 09:55:09:770 PST] this is today= 1393920000000
[14-03-04 09:55:09:770 PST] this is todayDaysTime + a week 1394524800000
[14-03-04 09:55:09:770 PST] Value of date in cell = 1394352000000
[14-03-04 09:55:09:770 PST] Value of date in cell = 1394434800000
[14-03-04 09:55:09:770 PST] Value of date in cell = 1394521200000
[14-03-04 09:55:09:771 PST] Value of date in cell = 1394607600000
I'm not sure why its not matching to future date properly. I'm looking to have an exact match so that when the day in the spreadsheet matches today's date + a week (7 days), it sends an email.
Any thoughts on why its not matching?
JavaScript date is a representation of the number of milliseconds counted from January the first 1970. Knowing that, it is very simple to get a value of 7 days before : you just have to subtract from today's value the right number of milliseconds, in your example 7*24*3600*1000.
To remember that and to check it yourself just type this simple statement in the script editor and run any other function then look at the logger :
Logger.log('reference JS date = '+new Date(0));// new Date(0) is the reference date for Javascript date objects.
Then a simple comparison inside the loop will do everything you need. You don't even have to define an else statement since the loop will continue by default.
The other important point is that the data you read from a spreadsheet is a 2D array, i.e. a matrix of matrix so you will have to use 2 indexes to get the right data. In the example snippet below I assumed dates were in column 1 so I used index [0] for the second index, the one that selects the column equivalent.
function myFunction() {
var data = SpreadsheetApp.getActiveSheet().getRange(1,1,4,4).getValues();
var sevenDayBeforeToday = new Date().setHours(0,0,0,0)-(7*24*3600*1000);// value in milliseconds, parenthesis are not necessary but make the code more readable imho...
Logger.log('sevenDayBeforeToday = '+sevenDayBeforeToday);
for (i=0 ; i<data.length; i++) {
Logger.log('Value of date in cell = '+data[i][0].getTime());
if (data[i][0].getTime() <= sevenDayBeforeToday) {
//send an email;
Logger.log('mail sent');
}
}
}
EDIT : here is a version that uses string comparison for easier debug and same result.
(note that I checked on a test SS the code above and it worked as expected when timeZone settings are set the same as spreadsheet, see logger below :)
function myFunction() {
var data = SpreadsheetApp.getActiveSheet().getRange(1,1,4,4).getValues();
var sevenDayAfterToday = new Date().setHours(0,0,0,0)+(7*24*3600*1000);// value in milliseconds, parenthesis are not necessary but make the code more readable imho...
Logger.log('sevenDayAfterToday = '+Utilities.formatDate(new Date(sevenDayAfterToday),Session.getScriptTimeZone(),'MM-dd-yyyy'));
for (i=0 ; i<data.length; i++) {
Logger.log('Value of date in cell = '+Utilities.formatDate(new Date(data[i][0]),Session.getScriptTimeZone(),'MM-dd-yyyy'));
if (Utilities.formatDate(new Date(data[i][0]),Session.getScriptTimeZone(),'MM-dd-yyyy') == Utilities.formatDate(new Date(sevenDayAfterToday),Session.getScriptTimeZone(),'MM-dd-yyyy')) {
//send an email;
Logger.log('mail sent');
}
}
}

Categories

Resources