How to stop formulas from updating at a certain time each day in Google Sheets? - google-apps-script

I want Google Sheets to stop updating a formula in a cell corresponding to the current date at a certain time each day, but I am not well versed in scripting so I need some help. I have some examples of my data below.
I have a sheet "Time Spent in Statuses" that automatically updates every hour (with a google sheets extension). New 'Keys' are added to the sheet when they are added in the extension, i.e Key '5' doesn't exist now, but when someone creates it in the data source linked with the extension, Key '5' and its corresponding values will be automatically added, so it updates frequently with more data.
In a separate sheet, I track the daily averages of numbers from the auto update in a sheet "Daily Averages" .
Currently in the "Daily Averages" sheet, I use a formula to calculate the average of each column in the "Time Spent in Statuses" sheet. This formula is pre-filled for days upcoming. At the end of each day, I have to go to this sheet and Copy and Paste > Values Only to record the averages for that day and stop the formula from continuing to update the next day. I use the 'Date' column and the Avg columns to show change in the daily averages over time in a dashboard.
What I'm looking for is some kind of logic that will look at the 'Date' column in the "Daily Averages" sheet and if it equals the current date and the time is 11:59 pm (or some other set time), then automatically Copy and Paste > Values Only. Or something similar so that I don't have to go in and manually paste values only every day. Does anyone have any experience doing something like this?

What you're looking for is a time-driven trigger in Apps Script. You can write a script and set it to run daily at a specific time.
There are multiple approaches that you can take when writing the script, but based on the sample that you provided, you can try the following code:
function setDailyAverage() {
let ss = SpreadsheetApp.getActiveSpreadsheet()
let avgsheet = ss.getSheetByName("Daily Averages")
//this is a string with today's date in format mm/dd/yyyy, like in your sample
let today = new Date().toLocaleDateString("en-US")
//this will do a search of today's date and return the row number
let row = avgsheet.createTextFinder(today).findNext().getRow()
let avgcell = avgsheet.getRange(row,2) //gets column 2 in the row corresponding to today
let giavgcell = avgsheet.getRange(row,3) //gets column 3 in the row corresponding to today
//This reads the values in each cell and overwrites the formula with the actual value
avgcell.setValue(avgcell.getValue())
giavgcell.setValue(giavgcell.getValue())
}
To add the script go to Extensions > Apps Script and paste it there, then on the left side go to Triggers > Add Trigger, then the trigger settings should look like this:
This would run the script every day between 11pm and midnight, and pretty much just automate the same "Copy and Paste > Values Only" process that you're following. You still would need to have the pre-filled rows for each date so keep that in mind. With the trigger you could also automate the creation of each row daily but I don't know if this would interfere with your workflow.

Related

Adding Date+Time without 12AM moving to the next day

I am using the attached to automate a time entry to go along with the date for a calendar import. The entries don't have times, and the staff will not enter them try as I might. I need to automate them to simplify the entry procedure.
The issue I am facing is that the Calendar API needs the data to be in DATE/TIME format. To do this I need to use the =DATE+TIME formula. When I do so and the time reaches 12:00AM, the dates thereafter change to the following day.
Essentially I need to either override the logic that makes it move into the next day after midnight appears, or I need to tell either the function in column B-C that it can never roll to midnight. I am trying to think of perhaps a way that I can tell the function to reset the time if the date in column A changes to a new day, and if it doesn't change to a new day go ahead and use the existing function and add 5 minutes to the time that is shown previously to it.
I am stumped, any help would be greatly appreciated.
Here is a sheet to show you the issue
Here is the formula I tried, which worked to sort out the problem but did not work with the Calendar API requirements to format at DATE/TIME. Even when using the importrange formula to move the data into a new sheet with the cells formatted as DATE/TIME it still recognizes it as TEXT as this is what the formula prescribes.
=IF(A2<>"",(CONCATENATE(TEXT(A2,"MM/DD/YYYY")&" "&TEXT(B2,"HH:MM:SS"))),"")
I need this to work in both the sheet and in the import to Calendar using the Calendar API requirements through APPScript.
If I understood correctly your question, here a suggestion with a custom Apps Script function called like a normal Google Sheet function.
Open Apps Script Editor and paste the function below
Call the function rebuildDateTime(COL1, COL2) inside your spreadsheet
Spreadsheet:
Code:
function rebuildDateTime(arg0, arg1) {
var date = new Date(arg0);
var str = arg1.toString().split(':');
date.setHours(str[0]);
date.setMinutes(str[1]);
return date;
}
Warning :
Your COL2 (which contains only the time), must be forced to TEXT FORMAT
References :
Create a custom function

Automate copying a value from one cell to another on a specific date

I'm looking for more of a pointer to some documentation of a method here rather than an exact solution, I'm happy with JavaScript, haven't done much Apps Script and I'm moderate to OK familiar with Google Sheets functions but far from expert.
I have part of a Google Sheet with some date specific data on it like this:
Date
Some-Value
1 Jan 2023
123
15 Jan 2023
456
... etc
In another part of a sheet I have a cell with the current value of Some-Value. This cell in fact contains a formula that totals a column on another sheet for the values. In case it's not blindingly obvious, these dates are in fact sprint end dates and the Some-Value is a count of story points extracted from JIRA. So sort of like this:
Current Value of Some-Value
345
On exactly the date in the Date column I want to copy the value from the "Current Value of Some Value" cell into the cell in the "Some Value" column adjacent to that date. I don't care if that copy happens only once on that day, or several times on that day, or every hour on that day, or whatever. I just want it to happen at least once, automatically.
Should I be looking at an Apps Script function to do this, and roughly how should I do that? Or is there a simpler way of using some Google Sheets function to copy that cell?
You could potentially do this with formulas if you are willing to enable iterative calculation for your sheet. In that case, you could then write something like =if(A2=today(),currentValueCell,B2) (I'm assuming your Date/Some-value table is in A1:Bx of a sheet and you are placing the above in B2). This will return the current value only if the date matches, and then when the dates no longer match will just maintain whatever value is already present in the cell.
EDIT
Ah yes, I forgot that the initial state of a self-referencing IF is zero (rather than null) until a TRUE occurs. Try =if(A2=today(),currentValueCell,if(B2<>0,B2,)) to hide the initial zero generated when the date in A2 is not equal to TODAY().
If you need to copy a value than then it's going to be changed or erased, yes, you'll need an AppScript. If you already know something, you'll more than able to set a simple function to do it.
You can look into Installable Triggers that will help you to set when and how frequently you want your script to be fired; and it will notify you if there are errors in any of that executions.
Sometimes, matching dates can be tricky, more if you have them previously written. If you have to do a timestamp, then you'll probably succeed at first. Just for have it handy: https://developers.google.com/google-ads/scripts/docs/features/dates
Remember to always use Logger.log() to track the progress of your code and what it's returning. Good luck and here you can always ask for specific struggles you may find!
(I'm no expert at programming by far, since it's copying only a value, you may find useful to record macros and watch them to learn how to copy in the formats you need - only values, paste format, etc. - if you don't copy, you can also research in .getValue() and .setValue() )
In case anyone else comes across this in future, here is the somewhat creaky Apps Script function I developed to do this. It's my first Google Apps Script function so feel free to tear it to shreds.
I then added a trigger to run this function weekly, which was easier than I had thought -- a bit of google searching for Apps Script time based triggers found me the answer.
Nonetheless thanks to the people who answered earlier because the clues you gave me helped me find the answer in the end.
function updateUnderTest() {
var activeSheet = SpreadsheetApp.getActiveSpreadsheet();
var sourceSheet = activeSheet.getSheetByName('Supporting Data');
// I12 is the cell that gets updated daily with the story point count
var value = sourceSheet.getRange('I12').getValue();
// D3:E27 is the range containing date : value pairs
var data = sourceSheet.getRange("D3:E27").getValues();
// epochNow will be the current epoch time, in milliseconds
var epochNow = new Date().valueOf();
// Look through the data range to find a matching date
for (nn=0;nn<data.length;++nn) {
// If a match is found to the nearest day, break the loop
if ((data[nn][0].valueOf() < epochNow) && ((epochNow - data[nn][0].valueOf()) < (24*3600*1000) )) {break};
}
// only update if we found a match
if (nn < 24) {
sourceSheet.getRange(nn+3, 5).setValue(value);
}
}

How do you track automated data inputs in Google Sheets over time?

I have a google sheet that runs a report on data that is automatically updated. What I would like to do is compare the new inputs with the old inputs to determine if the changes were positive or negative. How would you go about automating a sheet to track these changes?
Changes happen monthly
there would be a score 1-100; 100 being the best
would like to store this data over time for a historical view
Any advice would surely be appreciated
The numbers in each criteria change every month producing a score at the end of the table called Current Score
This score is then pulled into the historical tab as the "Current Score"
What I would like to see happen is that the Current score be saved every month and processed with a percentage change month over month
So I would need a function that stores a copy of the results before they change, processes a new score, and then calculates the difference between the two. Example here is the Dec score (stored values) compared to the most recent score.
Here is a link to the working example
https://docs.google.com/spreadsheets/d/1ImbRhWqGjvIx2CFRKapZ2wmxC9qpSKxxCbHr5tPOBOs/edit#gid=0
Solution
You can automate this process by using Google Apps Script. Open the script editor by clicking on Tools > Script Editor. It is based on JavaScript and allows you to create, access and modify Google Sheets files with a service called Spreadsheet Service.
In addition, you can use Time-driven triggers to run the script automatically once a month. To set it up, click Triggers in the left bar, then Add Trigger and select Time-driven in Select event source. You can now specify the month timer and the exact day and hour you want the script to run. However, I recommend that you do some testing before setting up the trigger to check that you get the desired results. You can test the code by clicking Run in the Editor.
Explanation of the code
There are three functions in the code. The main function is called updateScores and it does what you described in the question. It takes the current score, stores it in a new column and calculates the difference from the last month. Try this function and if you like the result, you can put the trigger in the main function. This way, the trigger calls main which its only responsibility is to call the other two functions. The first is updateScores, which I have already explained, and the second is clearScores, which clears all the values of Reports so you don't have to do it manually and you can start writing the new values for the new month.
I have added some comments so you can understand what each line does.
var lr = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('report').getLastRow()
function updateScores() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Historical')
var currentValues = ss.getRange('B2:B'+lr).getDisplayValues() // get current score
ss.insertColumnsAfter(2,2) // insert two new columns (current score and percent difference)
ss.getRange('D2:D'+lr).setValues(currentValues) // paste stored score
ss.getRange('C2:C'+lr).setFormula('=if(D2=0,"N/A",B2/D2-1)') // apply formula for last stored scores
ss.getRange('E2:E'+lr).setFormula('=if(F2=0,"N/A",D2/F2-1)') // correct formula reference
ss.getRange('E2:E'+lr).copyFormatToRange(ss,3,3,2,lr) // copy format percent
ss.getRange('F2:F'+lr).copyFormatToRange(ss,4,4,2,lr) // copy format scores
var month = new Date().toString().split(' ')[1] // get current month
ss.getRange('D1').setValue(month + ' score') // write current month on last stored scores
var diff = ss.getRange('E1').getDisplayValue() // get diff symbol
ss.getRange('C1').setValue(diff) // write diff
}
function clearScores(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('report')
ss.getRange('B2:G'+lr).clear()
}
function main(){
updateScores()
clearScores()
}

Button to "Archive" rows based on variable

I'm pretty new to Google Sheets and I'm looking for a method/function that will allow a button I create to archive all entries in the spreadsheet to another spreadsheet.
I currently have a column that calculates the current week of the year, and another manually entered column that is for the week of the year that the entry was input. This will eventually be calculated automatically on entry of a new row, but what I'm looking to do is pull all entries from weeks prior to the current week and place those rows into another spreadsheet I dictate.
I know this is possible in Excel, but I'm not the greatest with the programming in Google Sheets, so I'm looking for some advice/help.
EDIT:
Quickly I've discovered I'm either REALLY rusty or just not great at Java. I tried the following code:
function myArchive() {
var aYear = getYear()
var sourceSheet = SpreadsheetApp.getActive()
.getSheetByName('Payroll'),
destSheet = SpreadsheetApp.openById('PayrollArchive')
.getSheetByName(aYear),
sourceRanges = ['A:A', 'B:B', 'C:C'],
targetRanges = [7, 9, 12]
.map(function (r, i) {
var sr = sourceSheet.getRange(sourceRanges[i]),
val = sr.getValues();
destSheet.getRange(1, r, val.length, val[0].length)
.setValues(val);
sr.clear()
});
}
Retrieved from here: Is there an easy format to move columns of data by script?
However, I'm trying to do a little different.
I want to copy all entries where column 1 has the week # of the previous week or before. For example, it is currently the 21st week of the year. I want it to pull all entries in the spreadsheet where column 1 is 20 or previous. Not sure how to program the current week in Java.
I want to put ALL information from the rows pulled above into a sheet named the current year in the spreadsheet named PayrollArchive. So, all of the previous weeks' worth of rows would be put in the 2015 sheet in PayrollArchive spreadsheet. I think var aYear = getYear() is the proper coding to grab the current year but is it possible to grab the value of a particular cell in the sheet to get that? I already have the current week # and date information saved in cells within the spreadsheet. The week is saved in J1, and the date is saved in D1:E1 as the last day of the current work week. For example:
=TODAY()-WEEKDAY(TODAY(),3)+6
What happens when we want to archive the last week of 2015 during the first week of 2016? How do we prevent that 2015 information going into a 2016 sheet.
Will this CREATE the sheet if it does not exist? I currently have a 2015 sheet created, but will I need to manually create a 2016 sheet or will the function create the sheet on its own?
To add a custom menu to your spreadsheet, see the documentation:
Google Documentation - Custom Menus
To insert an image, open the help menu:
Do a search on "Insert Image"
You can add a custom menu, or insert an image that is linked to a script. There probably is a function or combination of functions that you could put into the spreadsheet to archive that would get data from the first spreadsheet, then you could copy all the formulas to values. That method would use formulas, then copy the formulas to values. It can all be done in code also, but you'd need to write a script to do that. So it's possible.
See posts like these:
Google Script to copy specific columns from one sheet to another sheet
Move columns of data by script
Copy from one sheet to another sheet

How can I record the contents of a Google Sheets cell at the end of each day?

In Google Sheets I'm collecting data dynamically using the IMPORTHTML function, and one element from that data set is currently copied in cell C1.
In another sheet I have a list of dates from now until 2017 as column A.
At the end of each day, I'd like to record the final C1 score in column B next to the relevant date.
How would I go about doing that in an automated way? That is, I want the spreadsheet to complete itself at the end of each day.
You need a script that copies the entry from sheet1!C1 into sheet2!columnB row(where columnA=today()).
Replace sheet1, sheet2 with your sheet names.
Setup spreadsheet
Within your spreadsheet goto
File>spreadsheet settings
Set your local and time zone, then set the recalculation onChange and every hour.
Use inbuilt function to locate today's row
goto sheet2!
I am assuming your columnA has the dates running from A1 to A# in date format.
We are going to need a cell to hold a value, I am choosing C1.
in C1 put this
=MATCH(today(),A:A)
This will give you a number, it should be the row holding today's date.
Build the script
Then goto
tools>script editor
create a script for spreadsheets. This will give you some sample script, delete this.
code is
function scorekeeper(){
var sheet1 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet1");
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet2");
var score = sheet1.getRange("C1").getValue(); // we want to store this
var row = sheet2.getRange("C1").getValue(); // this is our row
sheet2.getRange(row, 2).setValue(score );
}
You can test this by going to Run and selecting the function name. You may have to save the script first and give the app permission.
Setting the trigger
Let's make this run at midnight
goto
Resources>Current project's triggers.
Add a trigger.
Select;
scorekeeper()
Time-driven
Day timer
Midnight to 1:00 a.m.
And you are good to go.
If you're not comfortable with Google Apps Script, you can use the Append feature of the Google Sheet add-on Sheetgo (https://www.sheetgo.com/append-google-sheets/). To configure:
Install Sheetgo
Open the add-on (Add-ons -> Start -> Sheetgo)
Mousover the + button and down arrow for an Import Connection
Select the connection type 'Append'
Select the source spreadsheet and source tab from that spreadsheet
Select the frequency (in your case would be daily)
Click 'Connect'
The add on will create a new sheet with the data from the source sheet and automatically append a new record daily.
*disclaimer - I'm a co-founder of Sheetgo