Creating a time controlled trigger on Google Sheets - google-apps-script

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.

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

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();
}

Can I trigger Google Sheets scripts in a particular sequence?

I've altered a script that gets data from MailChimp and then displays it in Google Sheets. However, the the data comes out in a random order, rather than ordered (e.g. by "campaign date") and also creates duplicates.
So I added two scripts that
Clear the previous data
Sort in date order
I want to run these scripts in a specific order so:
The cell ranges clear
The data imports from mailchimp
The data is rearranged in date order
Ideally I'd like to refresh this data every 15 minutes. What's the best way to do this? I can post my code but it's quite bloated and messy.
I have a similar problem which I have solved by creating a "parent" function that runs all the other functions in order. For robustness I have also included a simple logging function that logs this to a sheet so I can easily see that the functions have run. However, if you're running this every 15 mins that could quickly get out of hand, so you could either bin the logging, or use the built-in Logger (see reference here)
function runAllFunctions() {
logit("Clearing data");
clearCellRange();
logit("Data Cleared. Importing MailChimp Data");
importMailchimpData();
logit("MailChimp data imported. Reordering data.");
orderData();
logit("Data reordered. Update complete");
}
;
function logit(message) {
var logBook = SpreadsheetApp.openById("<insert ID here>")
var logSheet = logBook.getSheetByName("Log")
logSheet.appendRow([new Date(),message]);
};

When sheet is opened, would like to auto-jump to certain cell based on date

UPDATE: Based on earlier answers, I joined the chorus of people asking Google to re-enable the ability to do this, and they have apparently complied.
Now to figure out how to implement it since I know nothing about scripting in Google Sheets.
ORIGINAL QUESTION BELOW
I have a spreadsheet with a number of different sheets that require daily entry of data. For example, there's a sheet called US-Sales, with a row for each day of the year. There are also several other identical sheets, like UK-Sales, US-Rentals, etc.
I would like focus to auto-jump to the proper row, based on the current date, whenever one of these sheets is opened.
Possible? If so, how?
This could normally be achieved by a simple script with an onOpen() function (that executes on spreadsheet opening) and activates the desired cell (or sheet)...
but, due to a change in the new version of spreadsheets (that you are most probably using) this is not possible anymore (for now), see this issue (3928) and feel free to star it so that hopefully Google team will change their mind and make it possible again ;-)
edit : this simple code works in old version of spreadsheets, it does not in new version.
function onOpen() {
SpreadsheetApp.getActive().getSheets()[0].getRange('B6').activate();// an arbitrary cell
// not worth trying more complex cell selection (on date or anything else) while this is blocked by design .
}
Details on this change here and below.
EDIT 2 :
On october 16 2014 this issue is now fixed and the code above works also in new version of spreadsheets. details of issue here
to automatically activate the row corresponding to the day of the year you can use a code like below :
function onOpen() {
var day = new Date().getDOY();// this uses a custom date method that returns the day of the year and is defined below
SpreadsheetApp.getActive().getSheets()[0].getRange(day,1).activate();// in cloumn 1 for example. Add an offset if necessary (if headers...)
}
Date.prototype.getDOY = function() {
var onejan = new Date(this.getFullYear(),0,1);
return Math.ceil((this - onejan) / 86400000);
}

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())