Google sheets custom function built-in function - google-apps-script

I have following custom function in google sheets, I tried to call a built-in function "TEXT" in my custom function but it is not successful. The Google sheets will prompt "unknown" function "TEXT". Is there a solution for this?
function NextMonth(StockTradeDate) {
var DeltaDate;
if (**TEXT**(StockTradeDate,"mmm") = "JAN" ) {
DeltaDate = 30;
}
return DATEVALUE(StockTradeDate) + 31;
}

Google Apps Script has the Utilities library which includes the formatDate method
Utilities.formatDate(date, timeZone, format)
For details see https://developers.google.com/apps-script/reference/utilities/utilities#formatdatedate-timezone-format
It's worth to say that in Google Sheets it's no possible call a built-in function within the script. If a service like Utilities doesn't include the functions that you are looking for, then the alternative is to build your own version, get it borrowed from a library, a open source project or any other place.
I made an attempt to use the spreadsheet function library from Ethercalc and shared about this on my answer to Is there a way to evaluate a formula that is stored in a cell?

Try using javascript date methods (as below) to drive the date and conditionals you need. Could not locate documentation that supports the Sheets built-in function calls from within an apps script function. Javascript is supported.
function NEXTMONTH(StockTradeDate) {
var DeltaDate
if (StockTradeDate.getMonth() === 0 ) { //Jan:0 Feb:1 ... Dec:11 these will need more conditionals.
DeltaDate = 30;
}
var date2 = new Date(StockTradeDate.valueOf()+ DeltaDate*24*60*60*1000)
// valueOf() is millisec time since 1/1/1970
return date2
}
If you need more info regarding the date methods and implementation, w3schools has an efficient reference.

Related

Access Spreadsheet Cell values from library script

Is there a way I can access data, stored within a spreadsheet-file from the library script?
I want to use 1 Google Apps Script from multiple Google Spreadsheet files within my Google Drive.
I followed this answer: "you could use Libraries. The idea is that you create one script that you use as a library" and could successfully import the library to my project.
In order to work, the scripts within the library need some of the cell-values stored in the google sheet files. I know how to access the script via a helper function in my sheet-bound script file. For example:
function loc_my_credits()
{
SISTRIXAbfrageFreigabe.my_credits();
}
Whilst "SISTRIXAbfrageFreigabe" is the library name, and my_credits a function within the library.
When I call loc_my_credits from sheets, nothing happens. My best guess: the script cant read data from the spreadsheet file it needs to execute.
The my_credits script from the library file looks like this:
function my_credits(){
// Base URL to access customsearch
var urlTemplate = "https://api.sistrix.com/credits?api_key=%KEY%";
// initialize sheets: 1. Get the spreadsheet, 2. Get the first and the second sheets in this spreadsheet
var spreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var inputSheet = spreadSheet.getSheets()[0];
// Script-specific credentials & search engine
var sistrix_Apikey = inputSheet.getRange('A2').getValue();
var url = urlTemplate.replace("%KEY%", encodeURIComponent(sistrix_Apikey));
var params = {
muteHttpExceptions: true
};
var xml = UrlFetchApp.fetch(url).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var items = document.getRootElement().getChildren();
for (var i = 0; i < items.length; i++) {
if(items[i].getName() == 'answer'){
var answer = items[i].getChildren();
return answer[0].getAttribute('value').getValue();
}
}
return 0;
}
Is there a way I can access the data stored in the spreadsheet file from the library script?
I'm writing this answer as a community wiki, since the issue was resolved from the comments section, in order to provide a proper response to the question.
The problem was related to the usage of methods that need scopes that require authorization, therefore it would be expected that simple triggers would show the error:
You do not have permission to call SpreadsheetApp.openById
Google's documentation states that installable triggers would solve the problem:
Installable triggers, however, offer more flexibility than simple triggers: they can call services that require authorization
According to s.Panse, the usage of installable triggers has resolved the issue in this case.
References:
google script openById : You do not have permission to perform that action
Installable Triggers

How to call ISOWEEKNUM from JS using Google Sheets

I want to call the google sheets function ISOWEEKNUM from JS in a custom function and can't get it working.
Current code is
function customFun(date) {
return ISOWEEKNUM(date);
}
However that just leads to an error:
ReferenceError: ISOWEEKNUM is not defined
How can I get that working and is there a reference how to call standard functions?
I believe your goal as follows.
You want to retrieve the week number using Google Apps Script.
You want to use the function customFun as the custom function.
For this, how about this answer?
Issue and workaround:
Unfortunately, in the current stage, the built-in functions of Spreadsheet cannot be directly used with Google Apps Script. And also, the custom function cannot put the formula. So in this case, it is required to use the workaround. Here, I would like to propose the following 2 workarounds.
Workaround 1:
In this workaround, when =customFun(date) is put to a cell, it is replaced with =ISOWEEKNUM(date) using the OnEdit event trigger.
Sample script:
In order to use this script, please put =customFun(today()) to a cell. By this, the formula of =customFun(date) is replaced with =ISOWEEKNUM(today()) by the OnEdit event trigger.
function customFun(date) {return ""}
function onEdit(e) {
const range = e.range;
const formula = range.getFormula();
const f = formula.match(/=customFun\(([\S\s\w]+)\)/);
if (f.length == 2) {
range.setFormula(`ISOWEEKNUM(${f[1]})`);
}
}
Workaround 2:
In this workaround, when =customFun(today()) is put to a cell, the week number is calculated by Google Apps Script and the result value is put to the cell.
Sample script:
function customFun(date) {
Date.prototype.getWeek = function() {
var onejan = new Date(this.getFullYear(), 0, 1);
return Math.ceil((((this - onejan) / 86400000) + onejan.getDay() + 1) / 7);
}
return date.getWeek();
}
getWeek() is from https://stackoverflow.com/a/7765814/7108653.
References:
Custom Functions in Google Sheets
Simple Triggers

Using built-in spreadsheet functions in a script

I'm using Google App Script for the first time.
I'm using it on a Google Doc spreadsheet.
I'm trying very simple functions, just to learn the basics. For example this works:
function test_hello() {
return 'hello';
}
But I'm puzzled by this simple one :
function test_today() {
return today();
}
It makes an #ERROR! wherever I use it.
And when I put my cursor on it, it says :
error : ReferenceError: "today" is not defined.
While the today() function works when used directly in the spreadsheet.
Does this mean that in scripts, I cannot use spreadsheet built-in functions?
Is there any elegant way around this?
Some spreadsheet functions are quite useful to me (I like weekday() for example).
A non-elegant way could be to create columns to calculate intermediate values that I need, and that can be calculated with spreadsheet functions. But I'd rather avoid something this dirty and cumbersome.
Google Apps Script is a subset of JavaScript, spreadsheet functions are currently not supported.
For example, if you want to create a function that returns today's date you should write :
function test_today(){
return new Date()
}// note that this will eventually return a value in milliseconds , you'll have to set the cell format to 'date' or 'time' or both ;-)
syntax is the same as with sheet functions : =test_today() see tutorial
There are many internet ressources on javascript, one of the most useful I found is w3school
Google Apps Script still does not (1/7/20) include an API to Google Sheets native functions.
But you can set the formula (native functions) of a cell named as a named range in a spreadsheet.
Then in the GAS:
var nativeOutput = spreadsheet.getRangeByName("outputCell").getValue();
Voila! Your GAS is calling the native function in the cell.
You can send data from the GAS to the native function in the cell, by naming another cell in the sheet (or in any sheet) referred to by the formula in the other cell:
spreadsheet.getRangeByName("inputCell").setValue(inputData);
Your GAS can dynamically create these cells, rather than hardcoding them, eg:
// Create native function, its input and output cells; set input value; use native function's output value:
// Use active spreadsheet.
var spreadsheet = SpreadsheetApp.getActive();
// Name input, output cells as ranges.
spreadsheet.setNamedRange("inputCell", spreadsheet.getRange("tuples!F1"));
spreadsheet.setNamedRange("outputCell", spreadsheet.getRange("tuples!F2"));
var outputCell = spreadsheet.getRangeByName("outputCell");
var inputCell = spreadsheet.getRangeByName("inputCell");
// Set native formula that consumes input cell's value, outputting in formula's cell.
outputCell.setFormula("=WEEKNUM(inputCell)");
// Call native function by setting input cell's value for formula to consume.
// Formula sets its cell's value to formula's output value.
inputCell.setValue(15);
// Consume native function output.
var nativeOutput = outputCell.getValue();
Logger.log("nativeOutput: "+ JSON.stringify(nativeOutput)); // Logs "nativeOutput: 3"
Beware: this technique exposes the code in cells that a spreadsheet user can access/change, and other spreadsheet operations could overwrite these cells.
What the spreadsheet functions can do, Javascript can do. I just have to replace var day_num = weekday() by var day_num = new Date(date).getDay()
Here is the result :
/**
* Writes the day of the week (Monday, Tuesday, etc), based on a date
*/
function day_name(date) {
// calculate day number (between 1 and 7)
var day_num = new Date(date).getDay();
// return the corresponding day name
switch(day_num) {
case 0: return 'Sunday'; break;
case 1: return 'Monday'; break;
case 2: return 'Tuesday'; break;
case 3: return 'Wednesday'; break;
case 4: return 'Thursday'; break;
case 5: return 'Friday'; break;
case 6: return 'Saturday'; break;
}
return 'DEFECT - not a valid day number';
};

google apps script: built-in spreadsheet functions fail in script - wrong syntax?

I am learning GAS and want to use spreadsheet functions within my script. As a test I did a simple case but on save it threw "reference Error: 'Left' is not defined." I've looked through examples of code and can't see an alternate syntax.
function testLeft(){
return LEFT("abcdef",3);
}
A second simple test, same result
function testNow(){
return Now()
}
Any suggestions? My wild guess is that there is a special syntax within scripts for using a built-in spreadsheet function. Or maybe not all functions available directly in spreadsheets are available for use in GAS?
Thanks.
Unfortunately spreadsheet functions are not available in Google Apps Script. In this case you can use JavaScript's substring() method to get the portion of the string you desire.
I am from a VBA background and I have found this site
http://excelramblings.blogspot.co.uk/2012/05/google-apps-script-equivalents-for.html
provided by Bruce Mcpherson very helpful lots of ready made functions for copying and pasting into your Google App Script especially if you are converting from an Excel spreadsheet to a Google spreadsheet.
Bruces Code for LEFT:
function Left(str,optLen) {
return Mid( str, 1 , optLen);
}
And to use the above LEFT function you will also need Bruces Mid function:
function Mid (str,optStart,optLen) {
var start = IsMissing (optStart) ? 0 : optStart - 1;
var length = IsMissing (optLen) ? Len(str) - start + 1 : optLen ;
DebugAssert( str.slice, str + ' is not a valid string for Mid function');
return str.slice ( start, start + length);
This is my attempt at simulating the mid Function
function fMid(varInStr, intPlace) {
//GAS does not have a Mid Function so I have made this one for now
//varInStr is the input string and you want a character returned from it at a given position
//intPlace is the position of the character you want
//Example
//=fMid("123456789", 9) returns "9"
var P
var N
P = intPlace -1
N = intPlace
return varInStr.substring(P,N)
};

Calling a Google App Script library from a Google spreadsheet cell

Trying out the new library feature in a Google spreadsheet. I have include a library with the identifier of "Test" and the library implements the function "foo()"
entering =Test.foo() into a spreadsheet cell gives the error : "unknown function name TEST.FOO"
If I create a function in my spreadsheet to wrap the library function:
function foo()
{
return Test.foo();
}
then use =foo() in my speadsheet cell, all is well. Creating wrapper functions for all library functions so they can be used in a spreadsheet cell makes using libraries less than ideal. Is there a way to call a library function from a spreadsheet cell?
There's not currently a way to call these library functions directly as a custom function from a cell. Creating a wrapper, as you've done, is the way to do this currently. If you'd like to be able to call library functions directly as custom functions, please raise that as an issue on the Issue Tracker.
Here is a workaround that allows you to call any library function if you paste in this one generic wrapper function. Then you can call this from the spreadsheet.
For example, if I had a library called MyLib with a function add(x, y) (pretend x is in cell A1 and y is in cell A2) I could call it like this:
=LIB_FUNC("MyLib", "add", A1, A2).
It's a little ugly but at least allows me to only have to paste this one function and then access any library function. Note that this depends on undocumented structure of the "this" object that is in scope when calling the wrapper function. Small chance this could break over time. Might see if I can publish this as an add on.
function LIB_FUNC(libraryName, functionName) {
var result;
var lib = this[libraryName];
var extraArgs = [];
if (lib) {
var func = lib[functionName];
if (func) {
if (arguments.length > 2) {
extraArgs = Array.apply(null, arguments).slice(2);
}
result = func.apply(this, extraArgs);
} else {
throw "No such function: " + functionName;
}
} else {
throw "No such library: " + libraryName;
}
return result;
}