Mode set to have the script make calls only every 2 minutes inside the every 1 minute trigger. (Google App Script) - google-apps-script

function All() {
var ss = SpreadsheetApp.getActive();
ss.getRange('Página1!A6').setFormula('=IF(ISEVEN(MINUTE(NOW())),"Ok","Error")')
ss.getRange('Página1!A6').copyTo(ss.getRange('Página1!A6'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
if (ss.getSheetByName('Página1').getRange("A6").getValues()[0][0]=="Ok"){
//History
ss.getRange('Página1!D1').setFormula('=IFERROR(FILTER({C:C;H1},{C:C;H1}<>""))');
ss.getRange('Página1!D1:D').copyTo(ss.getRange('Página1!C1'),
}
}
Google has triggers every 1 minute, 5 minutes, 10 minutes, 15 minutes and 30 minutes.
For this model, I use the 1 minute trigger!
To bypass this and be able to turn it on every 2 minutes instead of 1 minute (because it weighs a lot in the spreadsheet and occasionally creates errors), to deflect this I created this model where it analyzes if the minute of the current time is odd or even. If even, it activates the rest of the script, if odd it ends without doing anything else.
I would like to know if I could do this same thing, but instead of throwing the function into a cell, copy the value so that the formula NOW() doesn't keep updating all the time and so on ... same step but directly in the script, without moving the spreadsheet with unnecessary calls.
And if it would also be possible to do this to set the script to work every 3 minutes instead of 2 minutes as I managed to do.

Instead of using a sheet with a formula to determine if the minute is even or odd, you can use the Apps Script alternative.
I am using the %(Remainder) operator to get the reminder of a division by 2. If it's zero then the number is odd.
The equivalent for MINUTE(NOW()) is achieved with the Javascript Date new Date().getMinutes()
function myFunction() {
if (new Date().getMinutes()%2==0) { //If the minute is odd.
//Your code here
} //No need for else.
}

Instead of modifying your spreadsheet use the Properties Service to store the last time you script ran. Bear in mind that the Properties Service only stores strings, so you will have to convert the Date object to an string an viceversa.
Related
How can I modify a trigger so that it emails upon edit, but not so quickly?

Related

How to schedule a trigger on a script

The situation:
I have sheet containing JSON data that collects personal trading information from a stock exchange. When this API feed retrieves a new line of information (after a new trade has been placed) I need that to act as a trigger to run two Google Scripts to perform their function. These scripts can only be triggered when a new trade has been made, not on a regular time-based trigger.
What have I tried:
Initially, I started off trying onChange/onEdit however, both options will not work because onChange/onEdit search for user-made edits to the cell, which changes to an API feed are not. Because there is no material change to the formula and therefore onChange/onEdit do not react to trigger the script. I have also tried to find a solution for a trigger to activate a script on changes made within a formula (therefore to allow for new data to arriving through an API to trigger the script), but that doesn't appear to be possible.
What am I trying to achieve right now:
I am considering the possibility of establishing a time scheduled trigger via Scripts. Within the API feed, I get confirmation of the date and time a trade has been made. I plan for the script to search the lastRow of certain columns to identify a date and time to trigger this time scheduled script, which in turn will trigger the two other scripts mentioned above.
My coding:
function createTimeDrivenTriggers() {
// Trigger on 2019-12-11 at 21:00.
ScriptApp.newTrigger('priceCalc')
.timeBased()
.atDate(2019, 12, 11)
.atHour(21)
.create();
}
Explanation on coding:
Eventually, the information held within the .atDate() and .atHour() strings will contain information drawn from the lastRow of different columns on Google Sheets to identify the correct integer to feed in to this script. But for now, I am just trying to get this script to work based on fixed values.
In this example above, on 11th December 2019 at 21:00, the createTimeDrivenTriggers script should be triggered, which in turn runs the priceCalc script.
Questions:
1) I cannot get this script to work correctly at the date/time given. What am I doing wrong?
2) I also need to incorporate an .atMinute() and .atSecond() strings here, but that doesn't seem to be available. Can anyone advise how to incorporate this?
3) Finally, if anyone can think of a better way to find a solution for this other than a time scheduled trigger, I am happy to consider other options.
I am very much a novice of scripts, so helpful advise to sort my issue would be greatly appreciated. I have spent days trying to find a solution without any luck.
You can not use atDate(year, month, day) and atHour(hour) together
Indeed, the documentation specifies:
Frequency is required if you are using atHour() or nearMinute()
Instead, you can use at(date) with a date-time string, with the corresponding Javascript syntax.
Sample:
function createTimeDrivenTriggers() {
// Trigger on 2019-12-11 at 21:00.
var time=new Date('2019-12-12T21:00:00');
ScriptApp.newTrigger('priceCalc')
.timeBased()
.at(time)
.create();
}
When you run your code, it generates an error message:
Already chosen a specific date time with at() or atDate()....
What it means is that you cannot use both atDate() and atHour() in the same script.
The solution to creating a "time-of-day-and-hour" trigger is to use at().
The benefit of this is that you can specify a time interval down to seconds and milliseconds.
However, do not be misled. Google undertakes that the script will execute within +/-15 minutes from the specified time. So incorporating "second" parameters might make you feel good, but isn't guaranteed to make any real difference.
Props: #SpencerEaston (https://stackoverflow.com/a/30458103/1330560) for the definition of the date which may well be in the documentation, but I couldn't see it.
For example:
function createTimeDrivenTriggers() {
// Trigger on 2019-12-12 at 21:00.
//var d = new Date(year, month, day, hours, minutes, seconds, milliseconds);
var d = new Date(2019, 12, 12, 21, 00, 00, 00);
ScriptApp.newTrigger('triggertest')
.timeBased()
.at(d)
.create();
}

Creating a time controlled trigger on Google Sheets

I am importing JSON data to Google Sheets using this solution (https://blog.fastfedora.com/projects/import-json).
It is vital that this data is accurate all the time, however, I have noticed that the data provided through this function lags behind the actual API feeds.
The issue can be sorted if I delete and Ctrl+Z, but obviously I am not available 24/7 to constantly do that :).
A solution I have is that in the cells with the IMPORTJSON function, I have placed the following before it: IF(A1=1,"",IMPORTJSON....
So if 1 is entered in A1, everything is deleted, and once the 1 is deleted, the feeds refresh with the correct data.
Again the issue is that I have to manually enter this 1. I would like to create a method of this one is entered automatically. Like every minute or five minutes.
How do I go about creating this time triggering cell?
function updateCell() {
var range = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Name of Sheet").getRange("A1");
range.clear({contentsOnly: true});
range.setValue(1);
}
And set that function to trigger on a timer every x minutes.
See the documentation for further information if you need finer revisions.

Creating a script that runs every second

I am trying to create a script that edits a particular cell on a particular sheet every second with a random text like, "SetTime".
This Particular Cell is: X2
This Particular Sheet is: "System_Info"
You may ask why I need this, essentially, I have a cell that displays a time using the =NOW formula. When a spreadsheet is edited, it will refresh the =NOW formula.
So, I need a script that loops every second and runs a function that edits that cell.
I've used this:
setInterval(function(){ SpreadsheetApp.getSheet("System_Info").getRange('X2').setValue('SetTime'); }, 1000);
However, set interval is not defined.
Thanks for any help,
Shaun.
you are mixing server with client code. even if you use time driven apps script triggers its not possible because they run at most once a minute, and changes through api do not cause a refresh.
Alternative: go to spreadsheet menu,file,properties. Select the option to update calculated functions every minute. No script needed.
Here is a function that will update the time in a cell every second for 15 seconds. It should be at least a starting point for you.
function updateCell() {
for (i=0; i<15; i++){
Utilities.sleep(1000);
var date = new Date();
SpreadsheetApp.getActiveSheet().getRange("A1").setValue(date);
SpreadsheetApp.flush();
}
}

How can I enhance my auto hide script in Google Sheets so it wont time out

I have a script that I run on multiple Spreadsheets... it auto hides rows that contain a certain value. Currently this script it setup to run daily around 3:00 am, to ensure no one is active in it while it processes. The issue is I am now running into is these sheets are getting too large to use my current script, which runs line by line. The script times out and doesn't finish. I'm guessing it still runs the script on all the lines that are already hidden.
Here is my current script, which is pretty basic:
function autoHide() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("SHIPPING");
//get data from column
var data = sheet.getRange('AD:AD').getValues();
//iterate over all rows
for(var i=0; i< data.length; i++){
//compare first character, if greater than 0, then hide row
if(data[i][0] > 0){
sheet.hideRows(i+1);
}
}
}
I have tried searching for better options, and found where people were talking about using array filters, or running in batches, just different things that didn't seem to be explained enough for me to translate to what I was working on. I know running this line by line isn't the best way, especially with over a 1,000 rows and growing.
For a best case scenario, I would like to have a very efficient script that uses fractions of the processing my current script does. Otherwise, if there was just a way to run the script on the rows that are visible, that would be almost as good. Worst case scenario, if there is just a way to tell it to pick up where it left off when it gave a time out error... by placing some type of tag or something to know where to start back up.
I don't think linking a sheet is necessary, I just need to be able to hide any row that has a number greater than 0 in column AD, on a sheet called "SHIPPING".
While you could speed up the script itself (for example by batching consecutive rows that need to be hidden) that will also evenctually time out.
Instead, your script should remember in script properties the last row it processed, ao that if the script times out it will continue starting from that row.
You will also need to change the trigger times. Make it run every 10 minutes but only start processing if 1) its past 3am and b) the last row processed is not yet the very last row (which you reset to zero when finished).
this should handle huge sheets just fine. by 5am it would have run 12 times since 3am so it should be able to process 12 times more rows.
Note I chose 10min trigger so that a previous trigger (which could run for 6 minutes) wont ever overlap the next trigger.
Do make sure to set your timezone in the sheet and script file properties so that you use your timezones when checking if its past 3am already.

How to make google spreadsheet refresh itself every 1 minute?

My google spreadsheet is using GOOGLEFINANCE('symbol','price) function to retrieve stock prices of my portfolio. Unfortunately, I have to refresh manually now. How can I make the spreadsheet refresh itself every 1 minute?
Thank you for your help.
If you're on the New Google Sheets, this is all you need to do, according to the docs:
change your recalculation setting to "On change and every minute" in your spreadsheet at File > Spreadsheet settings.
This will make the entire sheet update itself every minute, on the server side, regardless of whether you have the spreadsheet up in your browser or not.
If you're on the old Google Sheets, you'll want to add a cell with this formula to achieve the same functionality:
=GoogleClock()
EDIT to include old and new Google Sheets and change to =GoogleClock().
If you are only looking for a refresh rate for the GOOGLEFINANCE function, keep in mind that data delays can be up to 20 minutes (per Google Finance Disclaimer).
Single-symbol refresh rate (using GoogleClock)
Here is a modified version of the refresh action, taking the data delay into consideration, to save on unproductive refresh cycles.
=GoogleClock(GOOGLEFINANCE(symbol,"datadelay"))
For example, with:
SYMBOL: GOOG
DATA DELAY: 15 (minutes)
then
=GoogleClock(GOOGLEFINANCE("GOOG","datadelay"))
Results in a dynamic data-based refresh rate of:
=GoogleClock(15)
Multi-symbol refresh rate (using GoogleClock)
If your sheet contains a number of rows of symbols, you could add a datadelay column for each symbol and use the lowest value, for example:
=GoogleClock(MIN(dataDelayValuesNamedRange))
Where dataDelayValuesNamedRange is the absolute reference or named reference of the range of cells that contain the data delay values for each symbol (assuming these values are different).
Without GoogleClock()
The GoogleClock() function was removed in 2014 and replaced with settings setup for refreshing sheets. At present, I have confirmed that replacement settings is only on available in Sheets from when accessed from a desktop browser, not the mobile app (I'm using Google's mobile Sheets app updated 2016-03-14).
(This part of the answer is based on, and portions copied from, Google Docs Help)
To change how often "some" Google Sheets functions update:
Open a spreadsheet. Click File > Spreadsheet settings.
In the RECALCULATION section, choose a setting from the drop-down menu.
Setting options are:
On change
On change and every minute
On change and every hour
Click SAVE SETTINGS.
NOTE External data functions recalculate at the following intervals:
ImportRange: 30 minutes
ImportHtml, ImportFeed, ImportData, ImportXml: 1 hour
GoogleFinance: 2 minutes
The references in earlier sections to the display and use of the datadelay attribute still apply, as well as the concepts for more efficient coding of sheets.
On a positive note, the new refresh option continues to be refreshed by Google servers regardless of whether you have the sheet loaded or not. That's a positive for shared sheets for sure; even more so for Google Apps Scripts (GAS), where GAS is used in workflow code or referenced data is used as a trigger for an event.
[*] in my understanding so far (I am currently testing this)
GOOGLEFINANCE can have a 20 minutes delay, so refreshing every minute would not really help.
Instead of GOOGLEFINANCE you can use different source. I'm using RealTime stock prices(I tried a couple but this is the easiest by-far to implement. They have API that return JSON { Name: CurrentPrice }
Here's a little script you can use in Google Sheets(Tools->Script Editor)
function GetStocksPrice() {
var url = 'https://financialmodelingprep.com/api/v3/stock/real-time-
price/AVP,BAC,CHK,CY,GE,GPRO,HIMX,IMGN,MFG,NIO,NMR,SSSS,UCTT,UMC,ZNGA';
var response = UrlFetchApp.fetch(url);
// convert json string to json object
var jsonSignal = JSON.parse(response);
// define an array of all the object keys
var headerRow = Object.keys(jsonSignal);
// define an array of all the object values
var values = headerRow.map(function(key){ return jsonSignal[key]});
var data = values[0];
// get sheet by ID -
// you can get the sheet unqiue ID from the your current sheet url
var jsonSheet = SpreadsheetApp.openById("Your Sheet UniqueID");
//var name = jsonSheet.getName();
var sheet = jsonSheet.getSheetByName('Sheet1');
// the column to put the data in -> Y
var letter = "F";
// start from line
var index = 4;
data.forEach(function( row, index2 ) {
var keys = Object.keys(row);
var value2 = row[keys[1]];
// set value loction
var cellXY = letter + index;
sheet.getRange(cellXY).setValue(value2);
index = index + 1;
});
}
Now you need to add a trigger that will execute every minute.
Go to Project Triggers -> click on the Watch icon next to the Save icon
Add Trigger
In -> Choose which function to run -> GetStocksPrice
In -> Select event source -> Time-driven
In -> Select type of time based trigger -> Minutes timer
In -> Select minute interval -> Every minute
And your set :)
I had a similar problem with crypto updates. A kludgy hack that gets around this is to include a '+ now() - now()' stunt at the end of the cell formula, with the setting as above to recalculate every minute. This worked for my price updates, but, definitely an ugly hack.
use now() in any cell. then use that cell as a "dummy" parameter in a function.
when now() changes every minute the formula recalculates.
example:
someFunction(a1,b1,c1) * (cell with now() / cell with now())