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
Related
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);
};
I am trying to convert data stored in "dd.mm.yy" format to "w" format in Google Sheets/Appscript. Unfortunately I cannot use the ".formatDate()" function since sheets does not recognice the input values as date values, so I tried the following:
function CheckWeekNuber() {
var dateStr =SpreadsheetApp.getActiveSpreadsheet().getSheetByName("INSERT RAW DATA HERE").getRange(3,5,300,4).getValues();
var day = dateStr.substring(0,2);
var month = dateStr.substring(3,5);
var year = "20"+dateStr.substring(6,8);
var weekNumb = Utilities.formatDate(new Date(year, month-1, day), "GMT", "w");
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("WEEKNUMBERS").getRange(3,5,300,4).setValues(weekNumb);
}
It worked perfectly with a foor loop, converting each single value at a time. But it was super slow. My problem lays in using the ".substring()" formula for arrays, it does not seem to work..
Do you have any idea how to fix it?
The use of substring() is not possible when applying directly to an array. Looping the only way in getting the substring() of each element on an array.
Suggestion
If you are open to changing the data in your sheet, you can try using createTextFinder(".").replaceAllWithText("/") on your data range to convert your data to date format. Once you have this, you will still loop into your new data to get the week number of each date. Code is as follows and this is working on my end:
function CheckWeekNuber() {
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("INSERT RAW DATA HERE").getRange(3,5,300,4);
range.createTextFinder(".").replaceAllWith("/") // converts str date to date format
var dateFormat = range.getValues();
var lastRow = range.getLastRow();
var lastCol = range.getLastColumn();
var weekNumb = [];
for(var row in dateFormat){
for(var column in dateFormat[row]){
dateFormat[row][column] = Utilities.formatDate(new Date(dateFormat[row][column]), "GMT", "w");
}
}
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("WEEKNUMBERS").getRange(3,5,300,4).setValues(dateFormat);
}
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
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!
I have a JavaScript function running in Google Drive folder of many spreadsheets that is currently logging dates into the log;
function convertDates(){
var ui = SpreadsheetApp.getUi();
SpreadsheetApp.getActiveSpreadsheet().toast('Conversion Started With First Row Date Cells','Conversion', 5);
Logger.log('Date Conversion Started');
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var cell = activeCell.getValue();
Logger.log(cell);
}
How would one convert the output of 'cell' which currently looks like:
May 03, 2014 at 05:19PM
Into a Unix Time stamp within Javascript? I am inclined to believe that this can involve the Date() function but am unsure.
Thank's in Advance.
You can do this way to remove "at" and the sheet then recognizes the value as a valid date.
function convertDates(){
var sheet = SpreadsheetApp.getActiveSheet();
var range_input = sheet.getRange(1, 1);
range_input = range_input.getValue();
range_input = range_input.replace("at ", " ");
sheet.getRange(1, 1).setValue(range_input);
}
I am just replacing for one single cell. You can loop that to all the needed cell values.
Hope that helps!
If you want the get a string representation of the number of seconds since the UNIX epoch (january 1, 1970) you can use a code like this :
function convertDates(){
var ui = SpreadsheetApp.getUi();
SpreadsheetApp.getActiveSpreadsheet().toast('Conversion Started With First Row Date Cells','Conversion', 5);
Logger.log('Date Conversion Started');
var activeCell = SpreadsheetApp.getActiveSpreadsheet().getActiveCell();
var unixEpoch = new Date(1970,0,1,0,0,0).getTime();// difference between JS epoch and UNIX epoch in milliseconds
var cell = ((activeCell.getValue().getTime()-unixEpoch)/1000).toString();
Logger.log(cell);
activeCell.setValue(cell);// this will write it back to the sheet... be careful, it is not a date object anymore but a string... so the code won't work after that.
}
You have to remove "at" and to add a space after "05:19".
Look like this :
var date = new Date("May 03, 2014 05:19 PM");