Google Apps Script spreadsheet date manipulation - google-apps-script

I have three scripts that are in a google docs spreadsheet. In this spreadsheet, in column H (or column 8), if I type an "x", the script changes it into that days date. After a few days, every date in column H has changed from a date to just a number. The numbers look like this: 40492, 40494, 40511. I am not sure what is causing this. Maybe it's something that is wrong in my script. I've pasted them below. Any ideas?
function onEdit(e) {
var colorA = "yellow";
var colorB = "#dddddd";
var colorC = "#dddddd";
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Purchase Orders");
var range = e.source.getActiveRange();
var sheetName = SpreadsheetApp.getActiveSheet().getName();
if (sheetName == "Purchase Orders") {
// 3 is column C
if (range.getColumn() == 3 && range.getValue() != "") {
sheet.insertRowAfter(range.getRow());
var r = range.getRow() + 1;
sheet.getRange("A" + r + ":H" + r).setBackgroundColor(colorC);
}
}
var col = e.source.getActiveRange().getColumn();
if(col == 3 || col == 8) {
var rows = sheet.getMaxRows();
//column C
var rangeC = sheet.getRange("C1:C"+rows);
var valuesC = rangeC.getValues();
//column H range
var rangeH = sheet.getRange("H1:H"+rows);
var colorH = rangeH.getBackgroundColors();
var valuesH = rangeH.getValues();
//iterate over each row in column C and H
//then change color
for (var row = 0; row < valuesC.length; row++) {
//check for columnC and column H
var hRow = colorH[row];
if (valuesC[row][0] != "" && valuesH[row][0] == "") {
hRow[0] = colorA;
} else if (valuesH[row][0] != "") {
hRow[0] = colorB;
}
}
sheet.getRange("H1:H" + rows).setBackgroundColors(colorH);
}
}
And this one
function onEdit(e) {
var ss = e.source.getActiveSheet();
var r = e.source.getActiveRange();
// 1 is A, 2 is B, ... 8 is H
if (r.getColumn() == 8 && r.getValue() == "x") {
r.setValue(Utilities.formatDate(new Date(), "MST", "yyyy-MM-dd"));
}
}
And this last one
ss = SpreadsheetApp.getActiveSpreadsheet();
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "New PO", functionName: "NewPO"}];
ss.addMenu("New PO", menuEntries);
}
function NewPO() {
SpreadsheetApp.getActiveSheet().insertRowsBefore(1,6);
// Adjust this range accordingly, these are the cells that will be
// copied. Format is getRange(startRow, startCol, numRows, numCols)
ss.getSheetByName("PO Form").getRange(1, 1, 6, 8)
.copyTo(SpreadsheetApp.getActiveSheet().getRange(1, 1, 6, 8));
}

In OnEdit, you probably want to set the format for that cell as well. setNumberFormat(numberFormat) appears to be the function you are after.
http://code.google.com/googleapps/appsscript/class_range.html#setNumberFormat

Related

How can I create a filter area in Google Sheets using Google Apps Script?

enter image description here
I want to create a filter area in A1 and A2 cells so that when I put drivers' name on these cells, the table (A:C) should be filtered according to the value entered in A1 and A2. Can someone explain me how to write Apps Script to perform such function?
Thank you in advance!
Try, with both names in C1 and C2 (pls, change sheet name as necessary)
function onEdit(e) {
var col = 3
var sh = e.source.getActiveSheet()
if (sh.getName() != "Sheet1") return;
if (e.range.columnStart > col || e.range.columnEnd < col) return;
if (e.range.rowStart > 2) return;
var names = sh.getRange(1, col, 2, 1).getValues().flat()
var range = sh.getRange(3, col, sh.getLastRow() - 2, sh.getLastColumn() - col + 1);
var filter = sh.getFilter();
if (filter !== null) filter.remove();
if (countNotOccurrences(names, '') == 0) return;
var hiddenNames = range.getValues().slice(1).map(row => row[0]).filter(who => names.indexOf(who) == -1);
range.createFilter();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues([...new Set(hiddenNames)]).build();
sh.getFilter().setColumnFilterCriteria(col, criteria);
}
const countNotOccurrences = (arr, val) => arr.reduce((a, v) => (v !== val ? a + 1 : a), 0);
Driver Data
function MyFunction() {
const ss = SpreadsheetApp.getActive()
const sh = ss.getSheetByName('Sheet0');
const osh = ss.getSheetByName('Sheet1');
osh.clearContents();
const sr = 3;
const dA = sh.getRange(1,1,2).getValues().flat();
const name = dA[0] + ' ' + dA[1];
const nameColumn = 1;
const vo = sh.getRange(sr,1,sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues().filter(r => r[nameColumn -1] == name);
osh.getRange(1,1,vo.length,vo[0].length).setValues(vo);
}
It can be something like this probably:
function onEdit(e) {
if (e.range.columnStart > 1) return;
if (e.range.rowStart > 2) return;
filter_table(e.value);
}
function filter_table(name) {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(3,1,sheet.getLastRow(),3);
var data = range.getValues();
var hidden_values = data.map(x => x[0]).filter(x => x != name);
var filter = sheet.getFilter();
if (filter !== null) filter.remove();
range.createFilter();
var criteria = SpreadsheetApp.newFilterCriteria().setHiddenValues(hidden_values).build();
sheet.getFilter().setColumnFilterCriteria(1, criteria);
}
It filteres the range A3:C every time you edit cell A1 or cell A2.
But I'm not sure though what do you want to get when the two cells contain different names.
Update
Here is the 'multi-filter' solution :
function onEdit(e) {
if (e.range.columnStart > 1) return;
if (e.range.rowStart > 2) return;
var sheet = SpreadsheetApp.getActiveSheet();
if(sheet.getName() != 'Filter') return; // <-- to limit the trigger only one sheet 'Filter'
var range = sheet.getRange(1,1,sheet.getLastRow(),3);
var [name1, name2, ...data] = range.getValues();
var hidden_values = data.map(x => x[0])
.filter(x => x != name1[0] && x != name2[0]);
var filter = sheet.getFilter();
if (filter !== null) filter.remove();
range.offset(2,0).createFilter();
if (name1[0] + name2[0] == '') return;
var criteria = SpreadsheetApp.newFilterCriteria()
.setHiddenValues(hidden_values).build();
sheet.getFilter().setColumnFilterCriteria(1, criteria);
}
If both of the cells are empty you will see all the rows.

I want to get a timestamp on edit in my datetime row, but I need it to also timestamp when I copy/paste multiple rows in google script

I'm trying to add timestamps to my datetime row on edit. What I'm getting right now is if one row is edited at a time it works. However, what I need is to timestamp every row when I copy/paste values in over multiple rows.
function getDatetimeCol(){
var SHEET_NAME = 'Queue';
var DATETIME_HEADER = 'datetime (+48h for archive)';
var headers = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getDataRange().getValues().shift();
var colindex = headers.indexOf(DATETIME_HEADER);
return colindex+1;}
function onEdit(e) {
var SHEET_NAME = 'Queue';
var ss = SpreadsheetApp.getActiveSheet();
var cell = ss.getActiveCell();
var datecell = ss.getRange(cell.getRowIndex(), getDatetimeCol());
if (ss.getName() == SHEET_NAME && cell.getColumn() == 1 && !cell.isBlank() && datecell.isBlank()) {
datecell.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
};
function onEdit(e) {
//e.source.toast('entry');
const sh = e.range.getSheet();
if (sh.getName() == 'Queue' && e.range.columnStart == 1) {
//e.source.toast('cond');
let col = {};
sh.getRange(1, 1, 1, sh.getLastColumn()).getValues()[0].forEach((h, i) => { col[h] = i + 1 });
for (var i = 0; i < e.range.rowEnd - e.range.rowStart + 1; i++) {
let rg = sh.getRange(e.range.rowStart + i, col['datetime (+48h for archive)']);
if (rg.isBlank() && sh.getRange(e.range.rowStart,1).getValue() != '') {
//e.source.toast('if');
rg.setValue(new Date()).setNumberFormat("yyyy-MM-dd hh:mm");
}
}
}
}

Google Apps Script - getLastRow where certain columns are empty

I have the following Google Apps Script which copies data from the source sheet and pastes it into another sheet. It currently looks for the last empty row and last empty column of the target sheet. I now have certain columns in the target sheet populated with formula to deal with the pasted data. The target sheet column range is A:K and has formula in columns I:K. in Can someone help me with new code to look for the last row where columns A:H are empty?
function onEdit(e) {
var spreadsheet = e.source;
var sheet = spreadsheet.getActiveSheet();
var sourcesheetname = "SOP Register"
var range = e.range;
var sheet = range.getSheet();
var row = range.getRow();
var column = range.getColumn();
var editedColumn = range.getColumn();
var editedRow = range.getRow();
var column = 7;
var date = range.getValue();
if(Object.prototype.toString.call(date) === '[object Date]' && editedColumn == column && editedRow > 2 && sheet.getName() == sourcesheetname) {
var targetsheetname = "Internal Audit Register";
var target = e.source.getSheetByName(targetsheetname);
var numCols = sheet.getLastColumn();
var values = sheet.getRange(row, 1, 1, numCols).getValues()[0];
values.splice(9) //Up to and including column I
values.splice(7, 1) //Remove column H
values.splice(2, 3); //Keep columns all columns and leave out columns C, D & E
var lastRow = target.getLastRow();
var lastCol = target.getLastColumn();
values.unshift("SOP"); //Append "SOP" to column A
target.appendRow(values); // Append new row
sheet.hideColumns(6,2);}}//End of onEdit Functions
After Tanaike's post I have added his function getLastRow(sheet) and all of my onEdit(e) script below:
function getLastRow(sheet) {
const values = sheet.getRange("A1:H" + sheet.getLastRow()).getDisplayValues();
let lastRow = 0;
for (let r = values.length - 1; r >= 0 ; r--) {
if (!lastRow && !values[r].every(e => e == "")) {
lastRow = r + 1;
break
}
}
return lastRow;
}
// Cut Employees Left from Unit Standards sheet and paste in Unit Standards - Employees Left sheet
function onEdit(e) {
var ss = e.source;
var sheet = ss.getActiveSheet();
var sheetName = "Unit Standards"
var range = e.range;
var editedColumn = range.getColumn();
var editedRow = range.getRow();
var column = 4;
var date = range.getValue();
// Object.prototype.toString.call(date) === '[object Date]' --> checks if value is date
// editedColumn == column && editedRow > 4 --> checks if edited cell is from 'Date Left'
// sheet.getName() == sheetName --> checks if edited sheet is 'Unit Standards'
if(Object.prototype.toString.call(date) === '[object Date]' && editedColumn == column && editedRow > 4 && sheet.getName() == sheetName) {
var numCols = sheet.getLastColumn();
var row = sheet.getRange(editedRow, 1, 1, numCols).getValues();
var destinationSheet = ss.getSheetByName("Unit Standards - Employees Left");
// Get first empty row:
var emptyRow = destinationSheet.getLastRow() + 1;
// Copy values from 'Unit Standards'
destinationSheet.getRange(emptyRow, 1, 1, numCols).setValues(row);
sheet.deleteRow(editedRow);
sheet.hideColumns(column); }
// Copy and paste from Events/Incidents sheet to Vehicle Damage sheet
{var range = e.range;
var sheet = range.getSheet();
var row = range.getRow();
var column = range.getColumn();
var sourcesheetname = "Events/Incidents";
var checkbox = range.getValue();
if (sheet.getName() == sourcesheetname && column == 25 && row > 2 && checkbox == true) {
var targetsheetname = "Vehicle Damage";
var target = e.source.getSheetByName(targetsheetname);
var numCols = sheet.getLastColumn();
var values = sheet.getRange(row, 1, 1, numCols).getValues()[0];
values.splice(17)
values.splice(8, 8)
values.splice(5, 1)
values.splice(3, 1); // Removing undesired values
var lastRow = target.getLastRow();
var lastCol = target.getLastColumn();
target.appendRow(values); }// Append new row
//SOP Internal Audit Required CheckBox if True
{var range = e.range
var sheet = range.getSheet();
var row = range.getRow();
var column = range.getColumn();
var sourcesheetname = "SOP Register";
var checkbox = range.getValue();
if (sheet.getName() == sourcesheetname && column == 5 && row > 2 && checkbox == true) {
sheet.showColumns(6,2);
sheet.getRange("F3").activate();}
// Copy and paste from SOP Register sheet to Internal Audit sheet
{var spreadsheet = e.source;
var sheet = spreadsheet.getActiveSheet();
var sourcesheetname = "SOP Register"
var range = e.range;
var sheet = range.getSheet();
var row = range.getRow();
var column = range.getColumn();
var editedColumn = range.getColumn();
var editedRow = range.getRow();
var column = 7;
var date = range.getValue();
if(Object.prototype.toString.call(date) === '[object Date]' && editedColumn == column && editedRow > 2 && sheet.getName() == sourcesheetname) {
var targetsheetname = "Internal Audit Register";
var target = e.source.getSheetByName(targetsheetname);
var numCols = sheet.getLastColumn();
var values = sheet.getRange(row, 1, 1, numCols).getValues()[0];
values.splice(9) //Up to and including column I
values.splice(7, 1) //Remove column H
values.splice(2, 3); //Keep columns all columns and leave out columns C, D & E
var lastRow = getLastRow(target);
var lastCol = target.getLastColumn();
values.unshift("SOP"); //Append "SOP" to column A
target.appendRow(values); // Append new row
sheet.hideColumns(6,2);}}}}}//End of onEdit Functions
This is my desired outcome and to paste the new data in cells A5:F5 but the current script is pasting it into cells A6:F6 and cells I6:K6 are empty:
Unwanted Outcome
A Sample of the source sheet and the target sheet are below:
Sample Spreadsheet
I believe your goal as follows.
You have a sheet which has the values in the columns "A" to "K". And the columns "I" to "K" have the formulas.
You want to retrieve the numbers of last row in the range of "A:H".
For this, how about this answer? In this answer, I prepare a function for retrieving the last row you want.
Modified script:
Please add the following function. This function returns the values of lastRow by inputting a sheet object.
function getLastRow(sheet) {
const values = sheet.getRange("A1:H" + sheet.getLastRow()).getDisplayValues();
let lastRow = 0;
for (let r = values.length - 1; r >= 0 ; r--) {
if (!lastRow && !values[r].every(e => e == "")) {
lastRow = r + 1;
break
}
}
return lastRow;
}
And, in order to use above function in your script, please modify as follows.
From:
var lastRow = target.getLastRow();
To:
var lastRow = getLastRow(target);
By this, lastRow can be retrieved in the range of "A:H".
Reference:
every()
Added 1:
About one more modification, please test the following modification. In your current script, lastRow retrieved by getLastRow(target) is not used and values is appended to the last row of the sheet by appendRow. So in order to use lastRow, please modify as follows. In this case, from your updated question, please modify getRange("A1:H" + sheet.getLastRow()) to getRange("A1:F" + sheet.getLastRow()) for the function of getLastRow.
From:
var lastRow = getLastRow(target);
var lastCol = target.getLastColumn();
values.unshift("SOP"); //Append "SOP" to column A
target.appendRow(values); // Append new row
To:
var lastRow = getLastRow(target);
var lastCol = target.getLastColumn();
values.unshift("SOP");
target.getRange(lastRow + 1, 1, 1, values.length).setValues([values]); // Modified
Added 2:
You have a sheet which has the values in the columns "A" to "K". And the columns "I" to "K" have the formulas.
You want to retrieve the numbers of last row in the range of "A:H".
And also, you want to copy the formulas of the columns "I" to "K" to the same row which puts the values.
For this, please modify your script as follows. In this case, please use above getLastRow().
From:
var lastRow = getLastRow(target);
var lastCol = target.getLastColumn();
values.unshift("SOP"); //Append "SOP" to column A
target.appendRow(values); // Append new row
To:
var lastRow = getLastRow(target);
var lastCol = target.getLastColumn();
values.unshift("SOP");
target.getRange(lastRow + 1, 1, 1, values.length).setValues([values]); // Modified
if (lastRow >= 3) target.getRange(lastRow, 9, 1, 3).copyTo(target.getRange(lastRow + 1, 9, 1, 3), SpreadsheetApp.CopyPasteType.PASTE_FORMULA); // Added
In this case, at least, it is required to have the row 3 has the formulas at the columns "I" to "K".
If the row 3 has surely the formulas at the columns "I" to "K", I think that you can also use if (lastRow >= 3) target.getRange(3, 9, 1, 3).copyTo(target.getRange(lastRow + 1, 9, 1, 3), SpreadsheetApp.CopyPasteType.PASTE_FORMULA);.

Google script - copy columnC data from Sheet21 to columnC Sheet2, if not present in Sheet2 already

I am writing one of my first scripts, and have tried to look at other similar questions.
I have two sheets:
sheet1: new data (Only Column C is of interest, everything else can ignore in other columns)
sheet2: old data (but needs to be updated with sheet1 new data if not already there). The data to be added should be at the end of Column C after the existing data.
The code I have has the following compiling error.
I need to - get the last row of Column C Sheet2. Then check if Column C sheet1 is present in ColumnC sheet2, if not present- copy over from sheet1 to sheet2 column C.
UPDATED CODE:
function updateSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = "Sheet1";
var destinationSheet = "Sheet2";
var source_sheet = ss.getSheetByName(sourceSheet);
var target_sheet = ss.getSheetByName(destinationSheet);
var last_row = CountColC();
//assumes headers in row 1
var r = target_sheet.getRange(1,2, lastRow - 1);
//Note the use of an array
r.sort([{column: 3, ascending: true}]);
// Process sheet
_updateSpreadsheet(source_sheet, target_sheet);
}
//gets last row in Column C
function CountColC(){
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for(var i = data.length-1 ; i >=0 ; i--){
if (data[i][2] != null && data[i][2] != ''){
return i+1 ;
}
}
}
function _updateSpreadsheet(source_sheet, target_sheet) {
var last_row = CountColC();
var source_data = source_sheet.getDataRange().getValues();
var target_data = target_sheet.getDataRange().getValues();
var resultArray = [];
for (var n = 1 ; n < source_data.length ; n++) {
var keep = true;
for(var p = 1 ; p < target_data.length ; p++) {
if (new Date(source_data[n][2]).getTime() == new Date(target_data[p][2]).getTime()) {
keep = false; break;
}
}
Logger.log(keep);
if(keep){ resultArray.push([source_data[n][2]])};
}
last_row++;
Logger.log(resultArray);
target_sheet.getRange(last_row,1,resultArray.length,resultArray[2].length).setValues(resultArray);
// target_data.push(n);
}
Thanks in advance :)
function updateSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = "Sheet1";
var destinationSheet = "Sheet2";
var source_sheet = ss.getSheetByName(sourceSheet);
var target_sheet = ss.getSheetByName(destinationSheet);
var lastCol = target_sheet.getLastColumn();
var lastRow = target_sheet.lastColumn();
//assumes headers in row 1
var r = target_sheet.getRange(2,1, lastRow - 1, 3);
//Note the use of an array
r.sort([{column: 3, ascending: true}]);
// Process sheet
_updateSpreadsheet(source_sheet, target_sheet);
}
//gets last row in Column C
function CountColC(){
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for(var i = data.length-1 ; i >=0 ; i--){
if (data[i][2] != null && data[i][2] != ''){
return i+1 ;
}
}
}
function _updateSpreadsheet(source_sheet, target_sheet) {
var last_row = target_sheet.CountColC();
var source_data = source_sheet.getDataRange().getValues();
var target_data = target_sheet.getDataRange().getValues();
var resultArray = [];
for (var n = 1 ; n < source_data.length ; n++) {
var keep = true;
for(var p = 1 ; p < target_data.length ; p++) {
if (new Date(source_data[n][2]).getTime() == new Date(target_data[p][2]).getTime()) {
keep = false; break;
}
}
Logger.log(keep);
if(keep){ resultArray.push([source_data[n][2]])};
}
last_row++;
Logger.log(resultArray);
target_sheet.getRange(last_row,1,resultArray.length,resultArray[2].length).setValues(resultArray);
// target_data.push(n);
}
Instead call
var last_row = target_sheet.CountColC();
Please use
var last_row = CountColC();

How to automatically add a timestamp in google spreadsheet

I have a sheet in my Google spreadsheet that contains 5 cells, the first 3 contains only words while the last 2 contains time, specifically a timestamp.
cell 1 = data
cell 2 = data
cell 3 = data
cell 4 = time start
cell 5 = time ended
Now, what I want is when cell 1 is supplied with data, a timestamp will automatically appear in cell 4. And when cell 2 and cell 3 is supplied with data, a timestamp will be the new value for cell 5.
My friend give me a code, that should pasted in Script editor:
function readRows() {
var sheet = SpreadsheetApp.getActiveSheet();
var rows = sheet.getDataRange();
var numRows = rows.getNumRows();
var values = rows.getValues();
for (var i = 0; i <= numRows - 1; i++) {
var row = values[i];
Logger.log(row);
}
};
And
function onOpen() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Read Data",
functionName : "readRows"
}];
spreadsheet.addMenu("Script Center Menu", entries);
};
function timestamp() {
return new Date()
}
and this code is pasted in =IF(B6="","",timestamp(B6))cell 4 and this one =IF(D6="","",timestamp(C6&B6)) is on cell 5. in his example tracker its working. But when i copied it to mine, the output in cell 4 and cell 5 is the Date today and not the time.
can anyone help me? why does it output the date and not the time?
You can refer this tutorial, if this helps.
In the script code, change
var timestamp_format = "MM-dd-yyyy"; // Timestamp Format.
to
var timestamp_format = "MM-dd-yyyy hh:mm:ss"; // Timestamp Format.
This should probably help you.
I just came across this problem and I modified the code provided by Internet Geeks.
Their code works by updating a specified column, the timestamp is inserted in the same row in another specified column.
What I changed is that I separated the date and the time, because the timestamp is a string, not a date format. My way is useful for generating graphs.
It works by specifying the column to track for changes, and then creating an upDate and upTime columns for the date and time respectively.
function onEdit(event) {
var timezone = "GMT+1";
var date_format = "MM/dd/yyyy";
var time_format = "hh:mm";
var updateColName = "Резултат";
var DateColName = "upDate";
var TimeColName = "upTime";
var sheet = event.source.getActiveSheet(); // All sheets
// var sheet = event.source.getSheetByName('Test'); //Name of the sheet where you want to run this script.
var actRng = event.source.getActiveRange();
var editColumn = actRng.getColumn();
var index = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(DateColName);
var timeCol = headers[0].indexOf(TimeColName);
var updateCol = headers[0].indexOf(updateColName);
updateCol = updateCol + 1;
if (dateCol > -1 && timeCol > -1 && index > 1 && editColumn == updateCol) {
// only timestamp if 'Last Updated' header exists, but not in the header row itself!
var cellDate = sheet.getRange(index, dateCol + 1);
var cellTime = sheet.getRange(index, timeCol + 1);
var date = Utilities.formatDate(new Date(), timezone, date_format);
var time = Utilities.formatDate(new Date(), timezone, time_format);
cellDate.setValue(date);
cellTime.setValue(time);
}
}
Hope this helps people.
Updated and simpler code
function onEdit(e) {
var sh = e.source.getActiveSheet();
var sheets = ['Sheet1']; // Which sheets to run the code.
// Columns with the data to be tracked. 1 = A, 2 = B...
var ind = [1, 2, 3].indexOf(e.range.columnStart);
// Which columns to have the timestamp, related to the data cells.
// Data in 1 (A) will have the timestamp in 4 (D)
var stampCols = [4, 5, 6]
if(sheets.indexOf(sh.getName()) == -1 || ind == -1) return;
// Insert/Update the timestamp.
var timestampCell = sh.getRange(e.range.rowStart, stampCols[ind]);
timestampCell.setValue(typeof e.value == 'object' ? null : new Date());
}
I made a slightly different version, based also on the code from Internet Geeks
In order to support multiple named sheets, and because Google Sheets Script doesn't currently support Array.prototype.includes(), I included the polyfill mentioned here
Also, in my version, the timestamp marks the date of creation of that row's cell, not the date of the last update as in the other scripts provided here.
function onEdit(event) {
var sheetNames = [
'Pounds £',
'Euros €'
]
var sheet = event.source.getActiveSheet();
if (sheetNames.includes(sheet.getName())){
var timezone = "GMT";
var dateFormat = "MM/dd/yyyy";
var updateColName = "Paid for ...";
var dateColName = "Date";
var actRng = sheet.getActiveRange();
var editColumn = actRng.getColumn();
var rowIndex = actRng.getRowIndex();
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues();
var dateCol = headers[0].indexOf(dateColName) + 1;
var updateCol = headers[0].indexOf(updateColName) + 1;
var dateCell = sheet.getRange(rowIndex, dateCol);
if (dateCol > 0 && rowIndex > 1 && editColumn == updateCol && dateCell.isBlank())
{
dateCell.setValue(Utilities.formatDate(new Date(), timezone, dateFormat));
}
}
}
// https://stackoverflow.com/a/51774307/349169
// https://tc39.github.io/ecma262/#sec-array.prototype.includes
if (!Array.prototype.includes) {
Object.defineProperty(Array.prototype, 'includes', {
value: function(searchElement, fromIndex) {
if (this == null) {
throw new TypeError('"this" is null or not defined');
}
// 1. Let O be ? ToObject(this value).
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If len is 0, return false.
if (len === 0) {
return false;
}
// 4. Let n be ? ToInteger(fromIndex).
// (If fromIndex is undefined, this step produces the value 0.)
var n = fromIndex | 0;
// 5. If n ≥ 0, then
// a. Let k be n.
// 6. Else n < 0,
// a. Let k be len + n.
// b. If k < 0, let k be 0.
var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0);
function sameValueZero(x, y) {
return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y));
}
// 7. Repeat, while k < len
while (k < len) {
// a. Let elementK be the result of ? Get(O, ! ToString(k)).
// b. If SameValueZero(searchElement, elementK) is true, return true.
if (sameValueZero(o[k], searchElement)) {
return true;
}
// c. Increase k by 1.
k++;
}
// 8. Return false
return false;
}
});
}