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.
Related
I need to be able to add a 4 character ID code to the end of a URL based on the current date.
I have an array with 31 codes (One for each day in July). Each day the URL should have the next string in the array added to the end. I'm not trying to add a random string or anything, I just want to correspond each string to a day of the month but have a single URL that changes dynamically.
Currently, I am able to add a single static ID to the URL but I don't know to proceed
Here what I have so far:
const btn = document.getElementById("dealbtn");
function changeImg() {
btn.href = "";
const ID = ["mp2y","ymhm","rdkx","rcvq","xf8g","zd9h","323c","uqqa","fvfr","vwdm","kqvu","wrwu","ia7v","m6db","vfmp","ifg8","8re4","hwrp","nzv8","a7da","bzek","anbt","a8vr","tfx3","4n42","anxq","3aa8","yxj6","hwqt","vmbi","b6qe"]
for(let i=0; i<ID.length; i++){
};
const day = new Date().getDate();
btn.href = `https://www.testsite.com/medialibary/uploads/Test-img-${day + ID[0]}.jpg`
};
changeImg();
Thanks for your help!
You need to get the ID using the day number as the index. Reduce the index by 1 to compensate for the fact that the calendar days start form 1 and arrays start from 0.
const ID = ["mp2y","ymhm","rdkx","rcvq","xf8g","zd9h","323c","uqqa","fvfr","vwdm","kqvu","wrwu","ia7v","m6db","vfmp","ifg8","8re4","hwrp","nzv8","a7da","bzek","anbt","a8vr","tfx3","4n42","anxq","3aa8","yxj6","hwqt","vmbi","b6qe"]
const day = new Date().getDate();
//btn.href = `https://www.testsite.com/medialibary/uploads/Test-img-${ID[day-1]}.jpg`
console.log('using '+ID[day-1])
I'm working with duration fields on Google Spreadsheet on my timezone
Here is an example of the data I'm working with and my Spreadsheet configuration
Sample data:
actividadID
destinoID
atractivoID
actividadDescripc
actividadDuracion
actividadTipo
da839da6
ae4f25ff
'46432440
Visita
1:00:00 a. m.
EspecĂfica
Script Objective
The idea is to loop through a subset of these fields so for that I'm grabbing all the values of the spreadsheet and filtering them:
function TourDuration(tourID, mySS) {
const touractivData = mySS.getSheetByName("TourActividad").getDataRange().getValues();
const activData = mySS.getSheetByName("Actividad").getDataRange().getValues();
var current_activList = touractivData.filter(function(item){
return item[1] == tourID; //Match Bot Numbers && Unprocessed trades
});
Logger.log("current_activList:");
Logger.log(current_activList);
When I check the result of the data I'm grabbing I see data that is off, going into negative not only by hours but also by minutes:
[da839da6, ae4f25ff, 46432440, Visita a la Plaza Mayor de Lima, Sat
Dec 30 01:08:36 GMT-05:00 1899, EspecĂfica]
(This one should be the equivalent to 1 hour, but instead I got a negative time)
My goal is to add all the durations that match my filter into a consolidated one without success.
Here is the full code at the moment:
function TourDuration(tourID, mySS) {
const touractivData = mySS.getSheetByName("TourActividad").getDataRange().getValues();
const activData = mySS.getSheetByName("Actividad").getDataRange().getValues();
var current_activList = touractivData.filter(function(item){
return item[1] == tourID; //Match Bot Numbers && Unprocessed trades
});
var current_activList_length = current_activList.length;
var total_duration = 0;
for(var i = 0; i < current_activList_length; i++){
var activDuration = activData.filter(function(item){
return item[0] == current_activList[i][2]; //Match Bot Numbers && Unprocessed trades
});
var duration = Utilities.formatDate(new Date(activDuration[0][4]), "GTM-5", "dd/MM/yyyy HH:mm");
var dur2 = new Date(activDuration[0][4]).toString().substr(25,6)+":00";
dateString = Utilities.formatDate(activDuration[0][4], dur2, "MM/dd/yyyy HH:mm:ss");
Logger.log(duration)
Logger.log(dur2)
Logger.log(dateString)
total_duration = total_duration;
}
}
And this is the result of the log for a register with a 45min duration:
Could it be that the App Script interface has a different timezone?
Although the minutes difference is hard to explain since usually the differences are in full hours.
Also, I don't plan on using getDisplayValue() since I need to consult the whole sheet and getDataRange() would be more efficient.
Explanation:
Also, I don't plan on using getDisplayValue() since I need to
consult the whole sheet and getDataRange() would be more efficient.
getDisplayValues is used instead of getValues() and its purpose is to get the displayed value as it is shown in the sheet.
Please refer to this post for more details:
Difference between getValue() and getDisplayValue() on google app script
On the other hand, getDataRange() is not a sophisticated function.
This expression:
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getDataRange().getValues();
is identical to this:
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getRange(1,1,activSheet.getLastRow(),
activSheet.getLastColumn()).getValues();
Towards the solution:
By using getDisplayValues you will be able to get the value as it is displayed in your sheet:
function TourDuration() {
const mySS = SpreadsheetApp.getActive();
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getDataRange().getDisplayValues();
console.log(activData[1][4]); // 1:00:00
}
However, you can't take the full date from this expression because the date is not specified in the cell. If you expand the change the format of your cells in column E to date:
you will see that you are getting exactly the info that is stored in the cell. So the code works as expected. The issue has to do with the missing information in the sheet itself.
You need to store the correct date in your sheet:
and then if you change the format back to time, the date will still be correct and your current script will be able to get it properly.
I would like to delete all rows of a Google sheet if their corresponding column1 value is NOT a valid date. Not sure how to fix this issue. Please check the attached image where I want to delete each of the three rows as their corresponding column1 value is not a Valid Date.
Please note that there are other rows of data with valid date in the format of YYYY-MM-DD at a Google sheets.
Explanation:
In your screenshot, 2238-01-03 is a valid date. In order to consider it as invalid you need to set up some manual rules. Since the column name is timestamp, I assume that all the future dates (tomorrow or later dates) are invalid dates.
Therefore, the following script will remove a row if the corresponding value in column A is either a valid future date or an invalid date ( e.g. hi).
The if condition to achieve that is:
dtObj>today || (!(dtVals[i] instanceof Date) && isNaN(dtVals[i]))
Solution:
function invalidDates() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('TempDataSet');
const sz=sh.getRange('A:A').getValues().filter(String).length;
const dtVals = sh.getRange('A2:A'+sz).getValues().flat();
const today = Utilities.formatDate(new Date(), ss.getSpreadsheetTimeZone(), "yyyy-MM-dd");
for (let i = dtVals.length - 1; i >= 0; i--){
var dtObj = Utilities.formatDate(new Date(dtVals[i]), ss.getSpreadsheetTimeZone(), "yyyy-MM-dd");
if ( dtObj>today || (!(dtVals[i] instanceof Date) && isNaN(dtVals[i])) ) {
sh.deleteRow(i+2);
}
}
}
Related:
Detecting an "invalid date" Date instance in JavaScript
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');
}
}
}
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