Hello dear community,
I am unfortunately not able to figure out where's the issue in #Serge insas AppScript to jump to Today's cell in my own spreadsheet.
Fixed potential issue with different timezones date format, however, the script jumps to the last cell as: sh.getRange(5,sh.getLastColumn()).activate(); indicates, but not to Today's cell.
Important to mention that my Spreadsheet is constructed horizontal, here is the link
Here is my version:
function JumpToToday() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
sh.getRange(5,sh.getLastColumn()).activate();
var data = sh.getDataRange("E5:NE5").getValues();
var offsetToSS = new Date('22/02/2022').setHours(0,0,0,0);
var today = parseInt((new Date().setHours(0,0,0,0)-offsetToSS)/86400000,10)+1;
for(var n=0;n<data[0].length;n++){
var date = data[0][n];
Logger.log("date = "+data[0][n]+" =? "+today);
if(date==today){break};
}
n++;
sh.getRange(1,n).activate();
}
Can the issue be due to the script going first to last column and then starts counting from n=0?
To get to the current date in your sheet.
You have to count the number of days from January 1 up to this day.
Use the number of days in the col parameter of Sheet.getRange(row, col, numRows, numCol) + the number of column used before the January 1 cell.
Here I created a code that will activate the cell with the current date with the help of user2501097's answer here:
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var snoopiSheet = ss.getSheetByName("Snoopi");
var range = snoopiSheet.getRange(5, getCurrentDayofYear() + 5, 1,1);
range.activate();
}
function getCurrentDayofYear(){
var date = new Date();
return (Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(date.getFullYear(), 0, 0)) / 24 / 60 / 60 / 1000;
}
Output:
Note: I used Snoopi sheet in the example above, I added + 5 in the 2nd parameter of getRange() because the start of the count is in the 5th column or January 1. Also, when using multiple Sheets, make sure to use ss.getSheetByName(name) this is to prevent script from applying the code to different sheets which might happen if you use getActiveSheet()
References:
Spreadsheet.getSheetbyName(name)
Sheet.getRange(row, column, numRows, numColumns)
Well I learned something new today. Date.valueOf() and Date.setHours(0,0,0,0) return the same, the value of date in milliseconds. But your date is invalid.
new Date("22/02/2022") returns Invalid date.
function dummy() {
try {
var offsetToSS = new Date('02/22/2022').valueOf();
console.log(offsetToSS);
var offsetToSS = new Date('02/22/2022').setHours(0,0,0,0);
console.log(offsetToSS);
var today = parseInt((new Date().setHours(0,0,0,0)-offsetToSS)/86400000,10)+1;
console.log(today);
}
catch(err) {
console.log(err);
}
}
8:14:09 AM Notice Execution started
8:14:09 AM Info 1645506000000
8:14:09 AM Info 1645506000000
8:14:09 AM Info 1
8:14:09 AM Notice Execution completed
Related
I am writing a small function using the Google Apps Script editor that checks that an event date in a spreadsheet is within 12 hours of the current date to send me a morning email notification. The for loop below loops through the dates column in my spreadsheet to find the current date (entered in the spreadsheet formatted as a date expressed as MM/DD/YYYY). I can't figure out why schedule[i][0].getTime() is giving me the following error:
TypeError: Cannot find function getTime in object .
Here's the function:
function sendEmail() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Schedule"); // get sheet
var lastRow = spreadsheet.getLastRow(); // find length of sheet
var schedule = spreadsheet.getRange(6, 1, lastRow, 5).getValues(); // this an array with dates and info on events (first column has dates)
var now = new Date().getTime(); // get today's date in ms
var MILLIS = 1000 * 60 * 60 * 12 // get number of milliseconds in 12 hours
for (var i=0; i <= lastRow; i++) {
var eventDate = schedule[i][0].getTime()
if (now - eventDate < MILLIS && now > eventDate) {
...send email...
};
};
};
I've checked to make sure that the schedule[i][0] object is a valid date (e.g. myvar instanceof Date, debugger, format in google sheet, etc.), and everything indicates that it is. Yet, any method I've tried that nests the if clause in a function or calls getTime() more than once in the if statement causes a TypeError.
What am I doing wrong that is causing this error? How can I edit my code so that the condition in my if statement only runs if the difference between now and the date in schedule[i][0] is less than 12 hours?
Here's a link to a spreadsheet showing how the data is formatted.
Thanks for your help!
Edit: I edited the question to match the "minimal reproducible example" format. The problem is with the for loop, which doesn't account for the header. Thanks to tehhowch for the fix.
This works on your data.
Using your data and a few minor tweaks to the code. I also used valueOf() instead of getTime() ...it's some thing I prefer using.
function sendEmail() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName("Sheet177");
var schedule = sh.getRange(6, 1, sh.getLastRow(), 1).getValues(); // this an array with dates and info on events (first column has dates)
var halfday = 1000 * 60 * 60 * 12;
var idxA=[];
for (var i=0;i<schedule.length;i++) {
var now=new Date().valueOf();
var sked=new Date(schedule[i][0]).valueOf();
var diff=now-sked;
if ((diff<halfday) && (now>sked)) {
idxA.push(i);//I am just collecting the indexes of the var schedule that are within 12 hours of now.
//send email
}
}
Logger.log(idxA);
}
Per tehhowch, the problem is that my for loop did not account for the header rows in my spreadsheet or that an array is 0-indexed.
Removing the empty rows in the array and giving the right limit in the for loop fixed the problem:
...
function sendEmail() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Schedule"); // get active sheet
var lastRow = spreadsheet.getLastRow(); // find length of sheet
var schedule = spreadsheet.getRange(6, 1, lastRow - 5, 5).getValues(); // get values from first column of dates
var now = new Date().valueOf(); // get today's date
var MILLIS = 1000 * 60 * 60 * 12 // get number of ms in 12 hours
for (var i=0; i <= schedule.length - 1; i++) {
var eventDate = schedule[i][0].getTime()
if (now - eventDate < MILLIS && now > eventDate) {
...send email...
};
};
};
Disclaimer: I'm a Google Apps Script newbie.
I'm trying to create a timesheet in Google Sheets that lets a user clock in & clock out to log hours on a given project. I've borrowed code from a YouTube video on the general structure of setting the whole thing up.
Here's what the blank time sheet looks like. It's pretty basic:
I've created a user button (off to the right) where the user presses "Start" and cell A2 will input a timestamp. Then the user can press an "End" button, and a second timestamp, this time in B2, will appear, along with a simple calculation in C2 that measures the delta in the two timestamps, thus giving a duration of time spent on a given task or project. Here's what it looks like:
When the user needs to press "Start" again, a new timestamp appears in cell A3, and so on so forth, along with a new delta calculation for each new row.
Problem: I'm unable to get the simple delta calculation in column C to increment down each new rows so that the setFormula function doesn't contain hardcoded references to cells A2 & B2. See below code for what I have so far:
function setValue(cellName, value) {
SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).setValue(value);
}
function getValue(cellName) {
return SpreadsheetApp.getActiveSpreadsheet().getRange(cellName).getValue();
}
function getNextRow() {
return SpreadsheetApp.getActiveSpreadsheet().getLastRow() + 1;
}
function addStartRecord (a) {
var row = getNextRow();
setValue('A' + row, a);
}
function addEndRecord (b, c) {
var row = getNextRow()-1;
setValue('B' + row, b);
setValue('C' + row, c);
}
function punchIn() {
addSRecord(new Date());
}
function punchOut() {
addERecord(new Date(), '=B2-A2');
}
The problem is with the punchOut() function there at the bottom. Any idea on the best way to increment this delta calculator down each new row?
Note: I saw a pretty good answer to a similar question here, but the code is throwing an error in the script editor after the line containing data[i] = ['=A' + i+1.toString() + ' + 1 ' ]. Also, I don't want to set a definitive last row for the delta calculation (such as 20 in this example). I'd want the user to be able to record as many new start/end times for a project as they'd want.
Edit: Here's a link to the timesheet so you can test the code.
Try modifying your punchOut method like this:
function punchOut() {
var ss = SpreadsheetApp.getActiveSheet();
var row = ss.getLastRow();
addEndRecord(new Date(), '=B' + row + '-A' + row);
}
I tested it in the sheet and it worked well.
setFormula() - this enables you to describe the formula to be inserted into column C.
The following is two simple functions that handle "Punch in" and "Punch Out" (with its calculation).
function so5695101401in() {
// punchin
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var lR = sheet.getLastRow();
// Logger.log("DEBUG: the last row is "+lR);
var punchinRange = sheet.getRange(lR+1, 1);
// Logger.log("DEBUG: the punchinRange = "+punchinRange.getA1Notation());
punchinRange.setValue(new Date());
}
function so5695101401out() {
// punchout
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var lR = sheet.getLastRow();
//Logger.log("DEBUG: the last row is "+lR);
var punchoutRange = sheet.getRange(lR, 2);
// Logger.log("DEBUG: the punchoutRange = "+punchoutRange.getA1Notation());
punchoutRange.setValue(new Date());
var timeElapsed = sheet.getRange(lR, 3).setNumberFormat("hh:mm:ss");
timeElapsed.setFormula("=B2-A2");
}
setFormula
I use a workaround for this problem, via app script copy the cell with the formula to de new row or range!.
for you problem:
var formula1 = sheetDatos.getRange(lastRow, 3); //get the formula
var copyRange = sheetDatos.getRange(lastRow+1, 3);
formula1.copyTo(copyRange);
for me is more easy in this way, try to do in sheet to understand how this work.
you need a initial formula to go in this way ;)
I'm creating a script in Google Sheets that will copy the active sheet and create 30 duplicate sheets within the same workbook. Each duplicated sheet will have a different name based on the value within a cell on the active sheet. The cell will contain a date; duplicated sheets will have names of dates after the date listed in the cell. Example, cell B3 is "7/5/2019". The duplicated sheets should be named, "July 6, 2019" (B3+1), "July 7, 2019" (B3+2), & "July 8, 2019" (B3+3), etc.
I'm using code that is already embedded within Google Sheets. Some of it was created by recording a macro and other parts were created through what little I know about coding and research online.
function duplicatesheet(){
//copy active sheet
var as = SpreadsheetApp.getActiveSpreadsheet()
SpreadsheetApp.getActiveSpreadsheet().duplicateActiveSheet();
//rename sheet
var myValue =
SpreadsheetApp.getActiveSpreadsheet().getRange('B3').getValue();
SpreadsheetApp.getActiveSpreadsheet().renameActiveSheet(myValue);
}
The code works in duplicating the active sheet once, but it is not making 30 duplicates. It is also not renaming the sheets properly as described above based on the date listed in cell B3. I need help creating code that will accomplish both of those tasks.
This is edited w.r.t. comments. You can also see the excellent answer by Tedinoz.
Try this code:
function duplicatesheet() {
var as = SpreadsheetApp.getActiveSpreadsheet(); // active spreadsheet
var s = as.getActiveSheet(); // first sheet object
var dateCell = "B3"; // cell containing first date
var N = 30; // number of copies to make
var startDate = new Date(s.getRange(dateCell).getValue()); // get the date stored in dateCell
var day = startDate.getDate(); // extract the day
var month = startDate.getMonth(); // extract the month
var year = startDate.getFullYear(); // extract the year
// loop over N times
for (var i = 0; i < N; i++) {
var asn = s.copyTo(as); // make a duplicate of the first sheet
var thisSheetDate = new Date(year, month, day+(i+1)); // store the new date as a variable temporarily
asn.getRange(dateCell).setValue(thisSheetDate); // writes the date in cell "B3"
asn.setName(Utilities.formatDate(thisSheetDate, undefined, "MMMMM d, yyyy")); // sets the name of the new sheet
}
}
I suggest putting N=30 there to something small, like N=2 to see whether it works with your formatting first.
The formatting here used by the Utilities.formatDate() method, I have assumed it to be MMMMM d, yyyy, which will print tab names in this format:
July 6, 2019
You may change it as you wish according to the reference [3] below.
You can see the references for all the functions used here:
Sheet.copyTo() method
Sheet.getRange() method
Java's SimpleDateFormat, used by Utilities.formatDate()
This code takes the single date entered by the OP in Cell "B3" of sheet name, say, "Sheet1; it loops thirty times creating a duplicate of the initial spreadsheet, incrementing the data-based sheet name by 1 day each time.
To ensure accurate date math, it's suggested that the format of Cell "B3" should be in the same style ("MMMM dd, yyyy") as the proposed sheet names.
function so5691088602(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetname = "Sheet1";
var basesheet = ss.getSheetByName(sheetname);
var newSheetName = new Date(basesheet.getRange("B3").getValue());
var NumDups = 30;
for (var i=0;i<NumDups;i++){
basesheet.activate;
var tempDate = new Date();
var printdate01 = Utilities.formatDate(new Date(tempDate.setDate(newSheetName.getDate()+1+i)), "GMT+10", "MMMM dd, yyyy");
// Logger.log("DEBUG: Sheet Date = "+printdate01);
ss.insertSheet(printdate01, {template: basesheet});
}
}
Screenshot
I am a relative newbie. I have a long list of expenses in a Google spreadsheet and I would like for it to jump to the appropriate place in this list based on the current month when I open the sheet. Each month has 200 rows, so I would like for it to do something like:
= MONTH(TODAY())*200
but this doesn't work inside the script. I have tried pulling it from a cell that performs this function, but I don't know how to do that. In the example below, I can jump to September because I defined
var monthrow = 1800
But how to do it for the rest of the months based on today's date? Thank you for your help!
function onOpen() {
goToSheet2b()
}
function goToSheet2b() {
var monthrow = 1800
goToSheet("Expenses", monthrow, 2);
}
function goToSheet(sheetName, row, col) {
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
SpreadsheetApp.setActiveSheet(sheet);
var range = sheet.getRange(row, col)
SpreadsheetApp.setActiveRange(range);
If I understood you correctly and if every month does indeed have 200 rows starting with January then the following should work for you. I've commented the code as well. Let me know if you have any questions.
function onOpen() {
var d = new Date(new Date().getTime());
var month = d.getMonth(); //.getMonth() returns values form 0 (Jan) to 11 (Dec)
var monthrow = month*200 + 1; //we add the 1 because if it is Jan than 0*200 = 0 + 1 = 1 or row number 1 and for the rest it will be the start of that month
goToSheet("Expenses", monthrow, 2);
}
Thank you!
I had to tweak order of operations. Here's the full thing that worked for me:
function onOpen() {
goToSheet2b()
}
function goToSheet2b() {
var d = new Date(new Date().getTime());
var month = d.getMonth(); //.getMonth() returns values form 0 (Jan) to 11 (Dec)
var monthrow = (month+1)*200;//we add the 1 because if it is Jan than 0*200 = 0 + 1 = 1 or row number 1 and for the rest it will be the start of that month
goToSheet("Expenses", monthrow, 2);
}
function goToSheet(sheetName, row, col) {
var sheet = SpreadsheetApp.getActive().getSheetByName(sheetName);
SpreadsheetApp.setActiveSheet(sheet);
var range = sheet.getRange(row, col)
SpreadsheetApp.setActiveRange(range);}
I've searched for this topic and have found a few threads - however, none of the answers (usually in the form of scripts) in those topics have proven to be successful to me yet. I guess I'm messing up some variables.
I have a spreadsheet in Google Docs that holds a work roster. In row B1:OI1 is just over a years worth of dates, i.e., B1 = Friday May 1st 2015, B2 = Saturday May 2nd 2015, OI = Wednesday June 1st 2016.
I want the sheet to jump to the roster of either today, or to the monday of the current week, whenever the sheet is opened.
How do I accomplish this?
Thanks in advance for the help!
I suppose you have seen this post where the OP wanted to change the background color of today's date in a sheet, your case is very similar except that - if I understood you well - today is not necessarily present in the sheet.
So what we need is to find the closest date to today ? You mention it has to be a Monday, I didn't go that far, the script below finds the closest date in column A, you will adapt it to your needs by simply adapting the index in the array. (don't forget arrays count from 0)
code :
function onOpen() { // runs automatically
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var data = sh.getDataRange().getValues();
var today = new Date().setHours(0,0,0,0);
var diffref = today;
var diff;
var idx;
for(var n=0;n<data.length;n++){
var date = new Date(data[n][0]).setHours(0,0,0,0);
diff=today-date;
if(diff==0){break}
Logger.log("diffref = "+diffref+" today-date = diff = "+diff);
if(diff < diffref && diff > 0){idx=n ; diffref=diff}
}
if(n==data.length){n=idx}
n++;
sh.getRange(n, 1).activate();
}
Edit :
To check the day of the week (yes, I'm curious by nature ;-) you can try to change the condition like this :
Logger.log("diffref = "+diffref+" today-date = diff = "+diff+" day = "+new Date(date).getDay());
if(diff < diffref && diff > 0 && new Date(date).getDay()==1){idx=n ; diffref=diff}
From my tests it seems to work as expected.
EDIT 2 :
Following your comment, it seems what you're looking for is much simpler :
function onOpen2() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var data = sh.getDataRange().getValues();
var today = new Date().setHours(0,0,0,0);
for(var n=0;n<data[0].length;n++){
var date = new Date(data[0][n]).setHours(0,0,0,0);
if(date==today){break};
}
n++;
sh.getRange(1,n).activate();
}
EDIT 3
For some reason that I ignore (please anyone give advise !!) your sheet does not return date values from the date in cells but rather the native spreadsheet values which are integers corresponding to the number of days since december 30,1899...
So what I did is to subtract this offset value from the javascript today variable, divide it by the number of milliseconds in a day (JS counts in milliseconds) and take the integer part of the result.
A bit cumbersome I admit but I didn't find a simpler way...
What is really weird is that in any other sheet I try dates are always returned as dates...
Anyway, for the time being, here is a working code for your spreadsheet :
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getActiveSheet();
var data = sh.getDataRange().getValues();
var offsetToSS = new Date('1899/12/30').setHours(0,0,0,0);
var today = parseInt((new Date().setHours(0,0,0,0)-offsetToSS)/86400000,10)+1;
for(var n=0;n<data[0].length;n++){
var date = data[0][n];
Logger.log("date = "+data[0][n]+" =? "+today);
if(date==today){break};
}
n++;
sh.getRange(1,n).activate();
}
Last note : for a better user experience, add this line of code right after var sh = ss.getActiveSheet();
sh.getRange(1,sh.getLastColumn()).activate();
this will select the last column before activating today's column and will place the selection on the left (near the frozen column in your sheet) which is more "natural".
function onOpen() {
// Activate cell with current date
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet(),
data = sheet.getDataRange().getValues(),
now = new Date(),
columnWithDate = 0,
i, delta,
epsilonInMs = 0;
for (i = 0; data.length > i; i++) {
delta = now - new Date(data[i][columnWithDate]);
if (delta < epsilonInMs) break;
}
sheet.getRange(i, columnWithDate + 1).activate();
}
This works when dates are in first column (column A) and you want to go to the row near the current date (you can tweak the numbers to suit):
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var d1 = new Date().getTime();
var a;
for (a = 1; (Math.floor((d1-sheet.getRange(a,1).getValue())/86400000)) > 5; a++)
try { var range = sheet.getRange(a+25,2); }
catch(err) { var range = sheet.getRange(2, 2) }
sheet.setActiveSelection(range);
}