Automatic Date Script - google-apps-script

I am trying to create a script to automatically advance dates in a spreadsheet by one. Is there any way to do this?
For example, in our spreadsheet, we may have 4 different dates that need to advance by one.
2/17/2017
2/14/2017
2/15/2017
2/18/2017.
Basically everytime I want to run this script, I want all dates in a spreadsheet to advance by one. Any help is appreciated!

I tested this with some financial data and it appears to work okay. It runs fairly fast.
If you want all of the dates in the spreadsheet then the first line of incrDate should be
var rng = SpreadsheetApp.getActiveSheet().getDataRange();
and I just went back and tested that as well.
This is the entire code for the code.gs file including menu. So you may want to doctor it up a bit.
I was a fun problem. Actually the hardest part was figuring out the isDate function.
Thanks
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Range Tools')
.addItem('Increment A Date by one day','incrDate')
.addToUi();
};
function incrDate()
{
var rng = SpreadsheetApp.getActiveRange(); // current selection
var rngA = rng.getValues();
if(rng.getNumRows() > 1 && rng.getNumColumns() > 1) // two dimension array
{
for(var i = 0; i < rngA.length; i++)
{
for(var j =0; j < rngA[i].length;j++)
{
if(isDate(rngA[i][j]))
{
rngA[i][j] = new Date(rngA[i][j].getTime() + (1 * 86400000));
}
}
}
}
if(rng.getNumRows() > 1 && rng.getNumColumns() == 1) //single column
{
for(var i = 0; i < rngA.length ; i++)
{
if(isDate(rngA[i][0]))
{
rngA[i][0] = new Date(rngA[i][0].getTime() + (1 * 86400000));
}
}
}
if(rng.getNumRows() == 1 && rng.getNumColumns() > 1)//single row
{
for(var i = 0; i < rngA[0].length ; i++)
{
if(isDate(rngA[0][i]))
{
rngA[0][i] = new Date(rngA[0][i].getTime() + (1 * 86400000));
}
}
}
if(rng.getNumRows() == 1 && rng.getNumColumns() == 1) //single cell
{
if(isDate(rngA[0][0]))
{
rngA[0][0] = new Date(rngA[0][0].getTime() + (1 * 86400000));
}
}
rng.setValues(rngA);
}
function isDate (x)
{
return (null != x) && !isNaN(x) && ("undefined" !== typeof x.getDate);
}

Related

Function that loops through the sheet

I'm trying to make Apps Script macro that will do following:
Check if checkmark (cell value = TRUE/FALSE) is ticked in column A
If it's ticked, increase value of cell in column H
Repeat until reached the last row.
After a little bit of digging around in documentation, I came up with this, and from my understanding it should be working, but since I'm asking a question here, it obviously does not. Script does get executed without errors, but it changes nothing on the sheet.
function increment() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var EndRow = ss.getLastRow();
for (var i = 2; i <= EndRow; i++) {
var Cell = ss.getRange(i,8);
var CheckmarkCell = ss.getRange(i,1);
if (CheckmarkCell.getValue() == 'TRUE') {
ss.Cell.setValue(ss.Cell.getValue() + 1);
}
}
}
Anyone has any idea, what's wrong here?
See if this helps?
function increMentWhenTrue() {
const sh = SpreadsheetApp.getActive().getSheetByName('Sheet1').getDataRange().offset(2, 0)
const values = sh.getValues().map(r => {
r[7] = (r[0]) ? (r[7]) ? r[7]+1 : 1 : r[7];
return r;
})
sh.setValues(values);
}
Change the sheet name in the first line to suit your requirements.
Same code with if-else statements
function increMentWhenTrue() {
const sh = SpreadsheetApp.getActive().getSheetByName('Blad1').getDataRange().offset(2, 0)
const values = sh.getValues().map(r => {
if (r[0]) {
if (r[7]) {
r[7] = r[7] + 1;
} else {
r[7] = 1;
}
} else {
r[7] = r[7];
}
return r;
})
sh.setValues(values);
}

Check duplicates between all sheets in google sheets

What I want to do is check for duplicates between all google sheets and if there are any - mark them in a color. For now, I left the headers to my columns just to see if it marks them red. I found one script that everyone said that worked - however, I got really random results with it. Could you possibly help with it?
The script:
Array.prototype.countItem = function (item) {
var counts = {};
for (var i = 0; i < this.length; i++) {
var num = this[i];
counts[num] = counts[num] ? counts[num] + 1 : 1;
}
return counts[item] || 0;
}
function findDuplicatesOnAllSheets() {
var nondupes = [];
SpreadsheetApp.getActive()
.getSheets()
.forEach(function (s) {
s.getRange('A1:E500')
.getValues()
.reduce(function (a, b) {
return a.concat(b);
})
.forEach(function (x, i, v) {
if (x && nondupes.countItem(x) == 0) {
nondupes.push(x)
} else if (x && nondupes.countItem(x) >= 1) {
s.getRange(i + 1, 3)
.setBackground('red');
}
});
});
}
This is the sheet I tested it on and you can see starting from sheet 3 that the results were random. The file should only have the headers as duplicates.
https://docs.google.com/spreadsheets/d/1naYaxR0f_wGsRP4-nBRZfAJ9ZqxpyA1uqQ9Uz5xvwNs/edit#gid=1044860260

How to break / exit out of a For loop in Googlesheets Script

How do I break out of a loop / stop a function when a specific logical condition is true in Googlesheets script. In my case, I have a program which, in a loop continuously sets the value of cell B1 and evaluates the result in cell D11.
What I want is that if the result is a string NNN, then the program must stop immediately.
Following is what I have, but the program doesn't exit / stop / quit when the logical condition is true (the program otherwise works fine). Any help appreciated.
function loopX() {
var xx;
var yy;
......
for (var i = 0; i < data.length; i++) {
sheet.getRange('B1').setValue(data[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(4000);
if (sheet.getRange('D11').getValue() == 'NNN')
exit();
}
......
}
Updated
function loopC() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('SheetN'); // name of your sheet
var data = ss.getSheetByName('data').getRange('A625:A2910').getValues()‌​;
if (sheet.getRange('D11').getValue() != "NNN") {
for (var i = 0; i < data.length; i++) {
sheet.getRange('B1').setValue(data[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(4000);
}
}
}
You can use break to go out from FOR LOOP. I think that this is a simple way.
Sample script :
var ar = [["e1"], ["e2"], ["e3"], ["e4"], ["NNN"], ["e6"]];
for (var i = 0; i < ar.length; i++) {
if (ar[i][0] == 'NNN') {
break;
}
}
Logger.log(i) // 4
Modified your script :
If this is reflected to your script, it can modify as follows.
function loopX() {
var xx;
var yy;
......
for (var i = 0; i < data.length; i++) {
sheet.getRange('B1').setValue(data[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(4000);
if (sheet.getRange('D11').getValue() == 'NNN') {
break;
}
}
......
}
But, in your script, I think that sheet.getRange('D11').getValue() might be able to be written to out of FOR LOOP like below. About this, since I don't know the detail your script, please confirm it.
if (sheet.getRange('D11').getValue() != 'NNN') {
for (var i = 0; i < data.length; i++) {
sheet.getRange('B1').setValue(data[i][0]);
SpreadsheetApp.flush();
Utilities.sleep(4000);
}
}

google script to find duplicates in google spreadsheet which occurs more than 2 times

I found the below google-app-script online which finds duplicates in the specified range of rows in a google spreadsheet. I need to edit this script in such a way that if the duplicates occur more than 2 times it should show those values.
This is how the script looks like:
function dups(rows) {
var values = {};
var duplicates = [];
for (var i = 0; i < rows.length; i++) {
var value = rows[i][0];
if (values[value] !== undefined && duplicates.indexOf(value) == -1) {
duplicates.push(value);
} else {
values[value] = true
}
}
return duplicates;
}
For example with this script if i type =dups(A1:A30)in any cell i get the list of unique values which are repeated more than once . But i want values which are repeated more than twice.
Thanks in advance,
drc
With triples unfortunately you can't just to a (simple) indexOf so the most efficient way is to count occurrences and stop when we hit two.
function trips(rows) {
var output = [];
var appearances;
for (var row = 0; row < rows.length-2; row++) {
var value = rows[row][0];
if (output.indexOf(value) > -1) {
continue;
}
appearances = 0;
for (var row2 = row + 1; row2 < rows.length; row2++) {
if (value === rows[row2][0]) {
appearances += 1;
}
if (appearances >= 2) {
output.push(value);
break;
}
}
}
return output;
}

Use formula inside script

I would like to use a formula inside a custom function, like this for example:
function myFunction(range, value) {
var countNumber = COUNTIF(range; value); // COUNTIF is a formula that can be used in the spreadsheet
if (countNumber > 0) {
return "RESULT";
} else {
return "OTHER RESULT";
}
}
And then:
=MYFUNCTION(A1:A5,"VALUETOTEST")
I would like to simplify a huge formula:
Something like:
=IF(SUM(COUNTIFS(G182:G186;"ERROR";H182:H186;"62");COUNTIFS(G182:G186;"ERROR";H182:H186;"ALL"))>0;"ERRO";IF(SUM(COUNTIFS(G182:G186;"RETEST";H182:H186;"62");COUNTIFS(G182:G186;"RETEST";H182:H186;"TODOS"))>0;"RETEST";IF(COUNTIF(G182:G186;"UNIMPLEMENTED")>0;"UNIMPLEMENTED";"SOLVED")))
You have three ways of performing these actions.
Add the Sheet Formulas to the sheet itself in the ranges that you need. Then read the data from the result cells (wherever you set it to write to) using your GAS Function. You can then perform further processing using the results.
Use your GAS function to write Sheet Formulas into your sheet. Then use more GAS to read that result and process the data. The method for this can be found here: https://developers.google.com/apps-script/reference/spreadsheet/range#setFormula(String)
You can create a Custom Sheet Formula using GAS that you then use in your sheet. GAS can then read that result and process the information. This will require some research into JS as a whole to know how to recreate, combine, and perform the operations that you need the data in the sheet to perform.
You can find a guide to make Custom Formulas here: https://developers.google.com/apps-script/guides/sheets/functions
And a guide to JS here: http://www.w3schools.com/js/default.asp
W3 Schools has a quite comprehensive guide to JS. GAS uses all native JS methods as it is a JS coding environment. Check the GAS Reference for more on GAS-specific methods that may perform what you need.
If what you need is to check conditions and/or iterate through rows, try something like this:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var range = sheet.getRange(startRow, startColumn, numRows, numColumns);
var values = range.getValues(); //This is a 2D array; iterate appropriately
for (i = 0; i < values.length; i++) {
if (values[i] == conditionToCheck) {
//perform code..OR
//continue; <- This works to skip the row if the condition is met
} else {
//perform alternate code if condition is not met
}
}
}
As I mentioned, .getValues() creates a 2D array. If you need to iterate through columns and rows, you will need 2 for() loops like so:
for (i = 0; i < values.length; i++) { //iterates through the rows
for(j = 0; j < values[i].length; j++) { //iterates through the columns in that current row
It is important to mention how GAS handles 2D arrays. values[i][j] denotes how much i rows there are and j columns. You can visualize like so:
values = [[A1, B1, C1],[A2, B2, C2],[A3, B3, C3]]
This is an array of arrays where the outer array is an array of the rows, while the insides are an array of cell values by column in that row.
Custom functions in google apps script do not have access to spreadsheet function. You may try using this =IF(COUNTIF(A1:A5,"VALUETOTEST")>0,"RESULT","OTHER RESULT")
If there is a huge formula for result, try creating functions for the result
function result1() {
return "RESULT";
}
function result2() {
return "OTHER RESULT";
}
Then use this =IF(COUNTIF(A1:A5,"VALUETOTEST")>0,RESULT1(),RESULT2())
Try this - copy the below function in apps script, and use this as Formula =myFunction("G182:G186","H182:H186") remeber to ensclose the range with ' " ' because you will be passing the range as string, and note both the ranges must be of equal length.
function myFunction(aRange, bRange) {
var cond_1 = "ERROR";
var cond_2 = "62";
var cond_3 = "ALL";
var cond_4 = "RETEST";
var cond_5 = "TODOS";
var cond_6 = "UNIMPLEMENTED";
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var aRange = sheet.getRange(aRange);
var aValues = aRange.getValues();
var bRange = sheet.getRange(bRange);
var bValues = bRange.getValues();
var count = 0;
var tmplength = 0;
if (aValues.length != bValues.length) {
return "Range length does not Match";
}
for (i = 0; i < aValues.length; i++) {
if (aValues[i] == cond_1 && bValues[i] == cond_2) {
count += 1;
}
if (aValues[i] == cond_1 && bValues[i] == cond_3) {
count += 1;
}
if (count > 0) {
return "ERROR";
} else {
count = 0;
if (aValues[i] == cond_4 && bValues[i] == cond_2) {
count += 1;
}
if (aValues[i] == cond_4 && bValues[i] == cond_5) {
count += 1;
}
if (count > 0) {
return "RETEST";
} else {
count = 0;
if (aValues[i] == cond_6) {
count += 1;
}
if (count > 0) {
return "UNIMPLEMENTED";
} else {
return "SOLVED";
}
}
}
}
}
This is how I solved my problem. I thank to people who helped me to reach this result!
// Like COUNTIFS
var countConditionals = function(cells, condition1, condition2) {
var count = 0;
for (i = 0; i < cells.length; i++) {
if (cells[i][0] == condition1 && cells[i][1] == condition2) {
count++;
}
}
return count;
}
// Like COUNTIF
var countConditional = function(cells, condition) {
var count = 0;
for (i = 0; i < cells.length; i++) {
if (cells[i][0] == condition) {
count++;
}
}
return count;
}
//Whole Formula
function verificaStatus(cells, db) {
const ERROR = "ERROR";
const ALL = "ALL";
const RETEST = "RETEST";
const NOTYET = "UNIMPLEMENTADED";
const SOLVED = "SOLVED";
var countErrors = countConditionals(cells, ERROR, db);
var countErrorsAll = countConditionals(cells, ERROR, ALL);
var sumErrors = countErrors + countErrorsAll;
if (sumErrors > 0) {
return ERROR;
} else {
var retest = countConditionals(cells, RETEST, db);
var retestAll = countConditionals(cells, RETEST, db);
var sumRetest = retest + retestAll;
if (sumRetest > 0) {
return RETEST;
} else {
var countNonCreated = countConditional(cells, NOTYET);
if (countNonCreated > 0) {
return NOTYET;
}
}
}
return SOLVED;
}