Getting row number when day changes on column 1 with dates - javascript

Is it possible to get the row number of the first row of a block of dates of the same day using GAS?
In this case I needed to get the row number "38" since its the first row of the block of rows for the 5th of September.
At the moment I am using:
function groupDays() {
sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('LOG');
rowStart = sheet.getLastRow() - 24;
rows = sheet.getLastRow() - rowStart + 1;
dates = sheet.getRange(rowStart, 1, rows, 1).getValues().flat();
groupDates(dates, 'date');
}
I did not post the whole script because it's a bit long. I'm using the script to group rows by day, month and year. Right now I am trying to work on the group rows by day part.
So the rowStartvariable is the row number from where the script will start grouping rows. This rowStart variable needs to advance as the rows keep getting recorded otherwise whenever the script is executed groups will be duplicated, triplicated, quadruplicated etc.
Problem is I think -24is not a good way to do this because sometimes data won't get recorded because of a Google Trigger error so a couple of rows might get skipped which will cause the grouping function to start at a row that is already grouped to the previous day which will duplicate the group for that previous day.
The script will be executed when comparing the 2 last rows it detects the last row advanced a day. Then it is supposed to create a group for the rows belonging to the day that just ended and which are ungrouped.
So again is there a way to use Google Apps Script to get the row number for the first row of a block of rows for the last day?
Here is my dummy file:
https://docs.google.com/spreadsheets/d/1ExXtmQ8nyuV1o_UtabVJ-TifIbORItFMWjtN6ZlruWc/edit?usp=sharing
EDIT:
I used one of the answers bellow with some changes:
function getRowDay() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("LOG");
var dateDay = sheet.getRange(sheet.getLastRow()-1, 1).getValue();
var dayPlusMonth = Utilities.formatDate(dateDay, Session.getScriptTimeZone(), "dd/MM/YYYY");
var cells = sheet.getRange("A5:A").createTextFinder(dayPlusMonth).findAll().map(x => x.getRowIndex());
var firstRowOfDay = cells[0];
//return cells[0];
// log start
console.log(dayPlusMonth);
console.log(firstRowOfDay);
console.log(sheet);
console.log(dateDay);
console.log(cells);
}

Answer:
You can extract the latest date by using .getLastRow() and then use the cell's value as a text finder parameter to find all cells that start with the date.
Code:
function getRow() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getSheetByName("LOG")
const date = sheet.getRange(sheet.getLastRow(), 1).getDisplayValue().slice(0, 11)
const cells = sheet.getRange("A1:A").createTextFinder(date).findAll().map(x => x.getRow())
return cells[0]
}
Rundown of this code:
Gets the sheet named LOG.
Gets the last cell in column A of this sheet, and extracts the first 10 characters of the cell (this will be the date portion without the time, e.g 06/09/2021)
Uses a text finder to search column A for all cells that contain this date
Maps these cell ranges to their corresponding row number
Returns the first cell in column A that starts with this date
References:
Class Sheet / createTextFinder(findText) | Apps Script | Google Developers

This is the simplest way to go. Just use the below findIndex() function and give it the day, month and year to look for and the data from the spreadsheet. Let me know if this is what you're looking for.
const findIndex = (day, month, year, rows) =>
rows.findIndex(
row =>
new Date(row[0]).getDate() === day &&
new Date(row[0]).getMonth() === month - 1 &&
new Date(row[0]).getFullYear() === year
) + 1;
const yourFunc = () => {
const rows = SpreadsheetApp.getActiveSpreadsheet()
.getActiveSheet()
.getDataRange()
.getValues();
const index = findIndex(5, 9, 2021, rows); // first row for 5th of September
console.log(index);
};

Related

How do I modify a column in an array to add a month and year to the day value?

I am working on a budget workbook in Google Sheets and need to take a list of monthly expenses and apply dates to those so I can aggregate with other types of expenses (one-time, bi-weekly, etc). The monthly expenses sheet is shown by 4 columns: Name, amount, day (monthly day the expense is due), and account. The list shows only one instance of each expense.
I want to take that array with the initial list and create 12 in-line copies on another sheet and modify each based on the month (e.g. modify first round of copies to add a "1/" + day + "/YY".
Some starting code with var names I'm using is below. I've tried several iterations with different functions (map, copy, etc), but have not had luck. Any help is appreciated! Thanks in advance!
function Add_Month_and_Year() {
var sheet = SpreadsheetApp
var orig = sheet.getActive().getSheetByName('Recurring -- Monthly');
var modified = sheet.getActive().getSheetByName('Recurring -- Monthly (BUILD)');
var originalArr = orig.getDataRange().offset(1, 0, spreadsheet.getLastRow() - 1).getValues();
Try this:
function Add_Month_and_Year() {
const ss=SpreadsheetApp.getActive();
const sh= ss.getSheetByName('Recurring -- Monthly');
const shsr=2;
let vs=sh.getRange(shsr,1,sh.getLastRow()-shsr+1,sh.getLastColumn()).getValues();
let oA=vs.map((r,i)=>{
let dt = new Date(new Date().getFullYear(),new Date().getMonth(),r[2]);
r[2]=dt;
return r;
});
Logger.log(oA);
ss.getSheetByName('Recurring -- Monthly (BUILD)').getRange(shsr,1,oA.length,oA[0].length).setValues(oA);
}

Use button and script editor to update a date value in cell Google sheets

I have a cell with a date in it, viewing only a part of the date (the year).
I also have a button next to it.
With this button I am trying to decrease (another button for increase) this dates value with exactly one year.
I have searched the whole internet for something that could help me out, but the closest I get is a line that looks like this, and that will update the cell but with something that is not formatted as I want. So I have tried different methods to "unwrap" the outcome and format the text to "date and time" and adjust the line to do the job with help from various guides and tutorials, but I can’t get it to work.
function plus() {
SpreadsheetApp.getActiveSheet().getRange('C2').setValue(SpreadsheetApp.getActiveSheet().getRange('C2').getValue() + 1);
}
Can I use Edate for something like this? Is that possible in script editor?
If your goal is to just increment/decrement the year of a date in C2 while retaining its date format, You can refer to this sample code:
function plus() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3");
var date = sheet.getRange('C2').getValue();
date.setFullYear(date.getFullYear()+1);
sheet.getRange('C2').setValue(date);
}
function minus() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet3");
var date = sheet.getRange('C2').getValue();
date.setFullYear(date.getFullYear()-1);
sheet.getRange('C2').setValue(date);
}
What it does?
When you get the value of the cell C2. It will give you a date object, Increment/Decrement the date's year using Date.prototype.setFullYear() and Date.prototype.getFullYear().
Set the value of the cell based on the updated date.
Output:
Before Increment:
After Increment:
Take the date from the cell and add a year in milliseconds to it with the setTime() function as below:
function plus() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("C2");
var oldDate = cell.getValue().getTime();
var newDate = new Date();
newDate.setTime(oldDate + (365*24*60*60*1000));
cell.setValue(newDate);
}

Google sheets dates, stored as strings by toString(), are not recognized as dates when written back into a cell?

I have a sheet that adds several thousand values per day. To keep it small and nimble, it regularly stores rows of data as comma separated values on a separate sheet. I loop through each row using toString() on all the cells.
When retrieving and reprinting the needed data to a new sheet, the sheets do not recognize the strings as dates.
e.g. Fri Mar 29 2019 13:45:06 GMT-0700 (PDT)
My workaround is slicing the strings when retrieving them, I am just wondering why they don't recognize the standard date strings as dates.
function compressData() {
var sheet = SpreadsheetApp.getActiveSheet();
var arr = sheet.getRange(1,1,2,2).getValues();
var arrNew = [];
var arrRow =[];
var arrExpanded;
for (var i in arr) {
for (var x in arr[i]) {
arrRow.push(arr[x][i]);
}
arrNew.push([arrRow[i].toString()]);
}
// stores each row of the original array as a
// comma separated string in a new array
sheet.getRange(1, 3, arrNew.length, arrNew[0].length).setValues(arrNew);
// writes the new array to a new range
}
function expandData(){
// prints the arrays onto a new range and the new date
// cell isn't recognized as a date
var arrExpanded = [];
var sheet = SpreadsheetApp.getActiveSheet();
var arrCompressed = sheet.getRange(1,3,2,1).getValues();
for (var i in arrCompressed) {
var arrTemp = arrCompressed.toString().split(',');
arrExpanded.push(arrTemp);
}
// rebuilds the 2d array
sheet.getRange(1, 4, arrExpanded.length, arrExpanded[0].length).setValues(arrExpanded);
}
You extract date values from a string, and are wondering why Google Sheets doesn't recognize the standard date strings as dates.
The reason is that the date that you see on-screen is actually a number, milliseconds from the Unix epoch. It is merely formatted to display so that it "looks like" a date consisting of text.
To convert a date string to a value that Google Sheets will recognise as a date, you need to convert it. The following code provides a simple example:
In the screenshot below, the value in Cell B1 is a string; the value is cell C1 is a date value. Note the actual data value (number) displayed in cell C5 (this cell is formatted as 'Number');
function so5842277201() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet1";
var sheet = ss.getSheetByName(sheetname);
var datestring = sheet.getRange("A1").getValue();
Logger.log(datestring);
var date01 = new Date(datestring);
Logger.log(date01);
var date02 = Utilities.formatDate(date01,"GMT-7", "EEE MMM d yyyy HH:mm:ss");
var newdaterange = sheet.getRange("C1");
newdaterange.setValue(date02);
}
Screenshot

Spreadsheet App converting Date()

Problem: Spreadsheet isn't recognizing an input date as a Date(), so I can't get the .getTime() from it in Apps Script.
Question: Can you see why this is?
Results:
Here is a part of the script I'm running:
dates.map(function(inp) {
if (inp != undefined && inp !== ""){
inp = new Date(inp.getTime() - (date.getTimezoneOffset()*60000);
return inp
}
});
where dates refers to a range: dates = sheet.getRange(2,1, lastR, 1).getValues();
Currently this range has a manually inputed value of "2017-05-20" which Spreadsheet automagtically recognizes as the date "Sat May 20 2017 00:00:00 GMT+0200 (CEST)"
The error reads as follows:
TypeError: Cannot find function getTime in object Sat May 20 2017 00:00:00 GMT+0200 (CEST). (line 86, file "Code") Details Dismiss
I have tried a million ways throughout my script to get Spreadsheet to stop autoconverting the input values as dates, so that I can make then at least timestamps or something. Does any one know why it is doing this?
Even if you call getValues() on a one-column range it will still be an array of arrays.
What's confusing here is that GAS tries to be helpful and displays the only value in the one-element array.
Extracting the first element from the row should fix this issue.
dates.map(function(row) {
var inp = row[0];
if (inp != undefined && inp !== ""){
inp = new Date(inp.getTime() - (date.getTimezoneOffset()*60000);
return inp
}
});
If you insist on doing everything via Array.prototype.map(), the following code might work. I ignored your date manipulation logic, adding 5 days to the date in the cell instead. For the values to update, you must assign whatever Array.prototype.map() returns to a variable. Also, 2 separate checks for empty string and 'undefined' are redundant as JavaScript actually considers them both to be 'false' (Unfortunately, this applies to 0 as well, so be careful)
function getDates() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2, 1, sheet.getLastRow() - 1, 1);
var values = range.getValues();
var newValues = values.map(function(row) {
var newRow = row.map(function(value){
if (value){
value = new Date(value.getTime() + 3600000*24*5) // adding 5 days
return value;
}
});
return newRow;
});
range.setValues(newValues);
}
I ended up taking Robin's recommendation, and did the following, which worked:
rows.map(function(r) {
r.day = new Date(r.day.getTime() - (date.getTimezoneOffset()*60000));
r.day = r.day.toISOString().split('T')[0];
return r
})
where date was globally defined as date = new Date(), "rows" the rows which have data in them, and "day" is the column name (of the first row [0] I had defined earlier in the script) for the column of dates I was trying to change.
Thanks again!

concatenate date and time in google spreadsheet

I have a script that imports events from spreadsheets into calendar:
function caltest1() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 3; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 5);
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar();
for (i in data) {
var row = data[i];
var title = row[0]; // First column
var desc = row[1]; // Second column
var tstart = row[2];
var tstop = row[3];
var loc = row[4];
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"), {description:desc,location:loc});
cal.createEvent(title, tstart, tstop, {description:desc,location:loc});
}
}
The script works fine if my spreadsheet contains the data like:
Title Description Start Stop Channel
Mr Dear no drinks 5/6/2014 20:55:00 5/6/2014 21:57:00 what ever
But it does not work if I create my own date =CONCATENATE($D4, " ",$G4), given that D4 has a date and G4 has time combined into a single cell Date and time. I figured because it senses that concatenate creates a plain text and not a time formatting, but how can I fix it?
In spreadsheets, dates have a native value of an integer representing the number of days since december 31 1899 and time is a decimal value which is the fraction of a day ( 6 hours = 1/4 of a day for example , 0.25 day).
So when you add DATE+TIME (integer+decimal) in a spreadsheet you get a full date with time .
So the answer (as you noticed it in your comment on the other answer) is logically to ADD both values. That's actually the reason spreadsheets are build like that ! (to make it easy to use date and time)
Use the formula =D2+E2 in a new column and you get a complete date object directly useable in JavaScript.
In Javascript date and time are the same objects, there is no time object that has no date and no date without time : their native values are milliseconds counted from January 1 1970 at midnight (which is an integer).
Since the type of concatenated strings is text, you can convert them to date before calling the Calendar methods.
var tstart = new Date(row[2]);
var tstop = new Date(row[3]);
I successfully concatenated date and time by using
=text(A2,"dd/mm/yy") & ", " & text(B2,"HH:MM")
I concatenated date and time

Categories