I have a column with date
var range = sheet.getRange(1,1);
range.copyTo(sheet.getRange(2,1));
give me the same date as previous row.
The above code works well for values and formulas, but not date.
How do I copy it such that it replicate the dragging behaviour, i.e. 11/6/2021 become 12/6/2021.
I have already formatted it as date, I can increment it by manually dragging the cell in UI, but I can't use copyTo in app script to achieve the same result.
In Apps Script, you need to convert to cell values to Date format in order to increment the date as google sheet is using Java Script by adding customize function, below is the way you can add Day + 1 in the next row using Javascript new Date() method:
function increRow(){
var ss = SpreadsheetApp.getActiveSheet();
var date = new Date( ss.getRange(1,1).getValue());
ss.getRange(2,1).setValue(new Date(date.setDate(date.getDate() + 1)));
}
You may try another method autofill which perform as human action to fill Range("A2:A4"), if you preferred:
function autoFill() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
spreadsheet.getRange(2,1).autoFill(spreadsheet.getRange(2,1,3,1), SpreadsheetApp.AutoFillSeries.DEFAULT_SERIES);
};
Related
I have a Google Sheets document that has 36 formulas across a row in the "Historical Data" tab. When I run the script each morning it populates the next empty row with the formulas in the previous row and then makes the previous row a value (so as to remove the formulas). I have an issue sometimes that the row with formulas loses the values and display "#N/A". I believe this is because the data is pulled from GoogleFinance.
Error in the image below.
I am curious if there is a method to do the following:
Define the formulas for each column in the code.
Run the script each morning and populate the next empty row with the values of the formulas.
The biggest item I need help with is adding the following formulas to the code so they will not be present in the worksheet. Additionally, some of the formulas rely on the value in a cell. For example the first formula is to create the date based on the date in the last row cell (A). The remaining formulas use the date from the new row columnm (a) and inputs from other columns in the new row. So when you see A2736 that is in last row and A2737 is the new row that was create when I last ran the script.
//DATE(A)=workday(A2736,1,'NYSE Holidays'!$A$2:$A$27)
//VIX9D(B)=INDEX(GOOGLEFINANCE("INDEXCBOE:VIX9D","close",$A2737),2,2)
//VIX1D(C)=INDEX(GOOGLEFINANCE("INDEXCBOE:VIX","close",$A2737),2,2)
//VIX3M(D)=index(GOOGLEFINANCE("INDEXCBOE:VIX3M","close",$A2737),2,2)
//VIX6M(E)=index(GOOGLEFINANCE("INDEXCBOE:VIX6M","close",$A2737),2,2)
//VIX1Y(F)=index(GOOGLEFINANCE("INDEXCBOE:VIX1Y","close",$A2737),2,2)
//VVIX(G)=index(GOOGLEFINANCE("INDEXCBOE:VVIX","close",$A2737),2,2)
//SPX(H)=index(GOOGLEFINANCE("INDEXSP:.INX","close",$A2737),2,2)
//VIX9D:VIX(I)=B2737/C2737
//VIX:VIX3M(J)=C2737/D2737
//VIX:VIX6M(K)=C2737/E2737
//VIX:VIX1Y(L)=C2737/F2737
//CORR, SPX , VVIX, 5(M)=correl(H2733:H2737,G2733:G2737)
//CORR, SPX , VIX, 10(N)=correl(H2728:H2737,C2728:C2737)
//Contango VIX2:VIX1(O) No formula yet
//Vix4:Vix7 Contango(P) No formula yet
//Log Ret(Q)=ln(H2737/H2736)
//V10(R)=stdev(Q2728:Q2737)
//V20(S)=stdev(Q2719:Q2737)
//HV10(T)=sqrt(252)*R2737
//HV20(U)=sqrt(252)*S2737
//VIX - HV10(V)=C2737-(T2737*100)
//VIX - hv20(W)=C2737-(U2737*100)
//VIX9D % Rank(X)=PERCENTRANK(B$2:B,B2737)
//VIX1D % Rank(Y)=PERCENTRANK(C$2:C,C2737)
//VIX3M % Rank(Z)=PERCENTRANK(D$2:D,D2737)
//VIX6M % Rank(AA)=PERCENTRANK(E$2:E,E2737)
//VIX1Y % Rank(AB)=PERCENTRANK(F$2:F,F2737)
//VVIX % Rank(AC)=PERCENTRANK(G$2:G,G2737)
//VIX9D Median(AD)=MEDIAN(B$2:B)
//VIX1D Median(AE)=MEDIAN(C$2:C)
//VIX3M Median(AF)=MEDIAN(D$2:D)
//VIX6M Median(AG)=MEDIAN(E$2:E)
//VIX1Y Median(AH)=MEDIAN(F$2:F)
//VVIX Median(AI)=MEDIAN(G$2:G)
//VDelta (VIX-VIX9D)(AJ)=C2737-B2737
Current code is below.
// Add Run button to menu
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu("Auto Trigger")
.addItem("Run","runAuto")
.addToUi();
}
// Define function to run with menu button
function runAuto() {
recordValue()
}
function createTimeDrivenTrigger() {
// Trigger every Weekday at 09:00.
ScriptApp.newTrigger('recordValue')
.timeBased()
.onWeekDay(ScriptApp.WeekDay)
.atHour(9)
.create();
}
// Record history from a cell and append to next available row
function recordValue() {
if (isNotHoliday()){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Historical_Data");
var lastRow = sheet.getLastRow();
var oldDate = sheet.getRange(lastRow,1).getValue();
var rng = sheet.getRange(lastRow,1,1,36);
rng.copyTo(sheet.getRange(lastRow+1,1,1,36));
rng.setValues(rng.getValues());
}
}
function isNotHoliday(){
var yesterday = new Date(new Date().getFullYear(),new Date().getMonth(),new Date().getDate()-1);
var formattedDate = Utilities.formatDate(yesterday, Session.getScriptTimeZone(), "M/d/yy")
var holidays = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('NYSE Holidays').getRange('A2:A').getDisplayValues().join().split(",");
return (! ~holidays.indexOf(formattedDate))
}
If you wish to run the script once every morning you could use programmatically triggers. This way you can easily set up a script run inside your desired time frame. Then you only would need to get the range of the last row and paste the formula there. I see that the script already gets the range, so you only need Range.setFormula() to drop the formula.
There is a much simpler way to do this - which is to flip time the other way.
You leave the google finance formulas in row 2 along with a =TODAY() in cell B2, with headers in row 1.
every night at 11pm, your sheet inserts a row above row 3, copies the values from row 2 into the new row 3 as values only.
That's it. super simple. you never need to copy formulas at all.
The newest prices are always at the top. This is how most people track portfolios.
I have a sheet "Sheet1" where a user inputs data in cells A3:E3. The goal is to then move that data into "Sheet2" where column A4:A34 is a numeric value for the day of the month. I want to move the data inputted on "Sheet1" into "Sheet2" on the row that corresponds with the current day of the month. Then "Sheet1" would clear itself for the next day ahead.
I'll be honest I'm not great with functions and I'm mainly looking for help on where to look to find a solution. I've tried different code that I do know how to use like Query but the issue is it doesn't lock the value in place and as soon as the values are wiped in Sheet1 they are then removed via the query.
You will need to run a function on a time-driven trigger. The function can use Range.getValues() to read the data, get the current date's day number with const dayNumber = new Date().getDate(), look up the day number in Sheet2 with Range.getValues().flat().indexOf(dayNumber), write the data with Range.setValues() and finally clear the source range with Range.clearContent().
It is unclear what the purpose the day numbers in Sheet2 serve, because the data would in any case be written once a day. It would seem simpler to always append the most recent data at the first available row and include a timestamp.
For an example of how to do this, see the appendRowsToArchiveSheet script.
Since the task is rather simple, here is the code that does the work:
// add menu Scripts
function onOpen() {
SpreadsheetApp.getUi().createMenu('🔨 Scripts')
.addItem('✅ Copy to archive', 'copy_range_to_archive')
.addItem('❌ Erase', 'erase_range')
.addToUi();
}
// erase the range A3:E3
function erase_range() {
SpreadsheetApp.getActiveSpreadsheet()
.getSheets()[0]
.getRange("A3:E3")
.clearContent();
}
// copy the range A3:E3 to Sheet 2
function copy_range_to_archive() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const src_range = ss.getSheets()[0].getRange("A3:E3");
const data = src_range.getValues();
const dest_sheet = ss.getSheets()[1];
const today = new Date().getDate();
const dest_range = dest_sheet.getRange(3 + today, 2, 1, data[0].length);
dest_range.clearContent();
dest_range.setValues(data);
}
It makes the menu 'Scripts' and two command 'Copy to archive' (the range A3:E3) and 'Erase' (the same range).
I am writing a script that pulls events from Google Calendar to Google sheets for a singular date. I want the user to be able to type the date on the spreadsheet (in this case, in the cell F1), and then when you run the script, the script gets all the events for the relevant date. However, with my current code, I can only type in the date in the script editor, as the script won't run when I try to reference F1 in lieu of the written-out date. What am I doing wrong?
function getEvents() {
var ss= SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var cal = CalendarApp.getCalendarById("email#email.com");
var events = cal.getEventsForDay(new Date("2/5/2020"));
for(var i = 0;i<events.length;i++){
var title = events[i].getTitle();
Logger.log(title);
ss.getRange(i+2, 1).setValue(title);
}
}
In short, I'd love to reference a cell in line 5, rather than the string of the date.
Sorry if this is so simple, I've never coded before so this is all new to me! Thank you for any help!
You want to retrieve the titles of events retrieving with getEventsForDay(Date).
You want to retrieve Date of getEventsForDay(Date) from the cell "F1" on the active sheet in the Spreadsheet.
You want to put the titles to the column "A" of row 2 on the active sheet.
You want to achieve this using Google Apps Script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modified script:
When your script is modified, please modify as follows.
From:
var cal = CalendarApp.getCalendarById("email#email.com");
var events = cal.getEventsForDay(new Date("2/5/2020"));
To:
var inputtedValue = ss.getRange("F1").getValue();
var cal = CalendarApp.getCalendarById("email#email.com");
var events = cal.getEventsForDay(inputtedValue);
When the value of the cell is the Date object, getValue() can be retrieved the value as the Date object.
If the value of cell "F1" is not the Date object, an error might occur. In that case, can you provide the sample Spreadsheet? By this, I would like to confirm it.
References:
getRange(a1Notation)
getValue()
I need to filter data from the latest sheet (a new one gets created every day automatically). The formula I use is
=FILTER('S&T 18/3/2019'!N:N;ISBLANK('S&T 18/3/2019'!N:N)=FALSE)
And it works, so in another cell I have´ve written another formula that keeps the first one up to date:
=CONCATENATE("=filter('S&T ";TEXT(TODAY();"d/m/yyyy");"'!N:N;ISBLANK('S&T";TEXT(TODAY();"d/m/yyyy");"'!N:N)=FALSE)")
In apps script I use the following code to paste the second formula as values, and it also works, but in its cell it shows as text instead of as a formula. If I manually delete the = form the beginning and then add it again it works perfectly. The idea is for it to work on its own. Can anyone help?
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Test Filtro'), true);
spreadsheet.getRange('D1').activate();
spreadsheet.getRange('D1').copyTo(spreadsheet.getRange('E2'), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
spreadsheet.getRange('E2').activateAsCurrentCell();
The Range#copyTo method accepts 2 optional arguments, the CopyPasteType and whether the data should be transposed. Your code fails to copy as a formula, because you use the CopyPasteType enum PASTE_VALUES. To copy a formula, you should use PASTE_FORMULA.
Enum CopyPasteType
PASTE_NORMAL Enum Paste values, formulas, formats and merges.
PASTE_FORMULA Enum Paste the formulas only.
PASTE_VALUES Enum Paste the values ONLY without formats, formulas or merges.
Your code would then look like:
...
var destCell = spreadsheet.getRange("E2");
spreadsheet.getRange("D1").copyTo(destCell, SpreadsheetApp.CopyPasteType.PASTE_FORMULA, false);
destCell.activateAsCurrentCell();
...
Since you are trying to do a "double paste" (your source data is a formula that creates a formula when it is evaluated, and you want to write the created formula), you need to paste the value of the original cell, then re-copy the output (your desired formula) and paste it as a formula:
...
const AS = SpreadsheetApp.CopyPasteType;
var destCell = spreadsheet.getRange("E2");
spreadsheet.getRange("D1").copyTo(destCell, AS.PASTE_VALUES, false); // Compute the desired formula, via formula-to-value conversion.
SpreadsheetApp.flush(); // Force the first copy to occur.
destCell.copyTo(destCell, AS.PASTE_FORMULA, false); // Activate the computed formula.
destCell.activateAsCurrentCell();
...
You may be able to avoid the first range copy entirely, by constructing the formula in script.
...
var TODAY = Utilities.formatDate(new Date(), "your timezone", "your format string here");
var myFormula = "=FILTER('S&T " + TODAY + "'!N:N;ISBLANK('S&T " + TODAY + "'!N:N)=FALSE)";
destCell.setFormula(myFormula);
...
Utilities.formatDate
I have two sheets in My Google Spreadsheet.
Master Tracking
Daily Tracking
Master Tracking pulls in information from other tracking sheets and updates the number of miles driven by each driver in cell M7.
I want to set up Daily Tracking with Date (Column A) and Number of Miles Traveled (Column B).
I want to write a Google Apps script which will copy the data from Master Tracking!M7 to Daily Tracking (column B) but into a NEW ROW every time the script is run. I'm planning on using a trigger for it to run at the end of every work day.
I have this till now but it doesn't work.
function copyFunction() {
var inputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Master Tracking").getRange("M7:M7");
var inputValues = inputRange.getValues();
var outputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getRange("B:B").getLastRow();
outputRange.setValue(inputValues);
}
I can't figure it out. I can get it to paste in one specific cell but I can't figure out how to paste it into a new row. Maybe getLastRow would work. I don't know.
Also, how to have a timestamp put in Column A of Daily Tracking?
Please help!
Didn't test it but should work : (see comments in code)
function copyFunction() {
var inputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Master Tracking").getRange("M7");
var inputValue = inputRange.getValue();// use simple getValue without S, get a simple value
var last = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getLastRow();// get the last row on this sheet
var outputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getRange(last+1,1,1,2);// getRange col A & B +1 after last row
outputRange.setValues([[Utilities.formatDate(new Date(), Session.getTimeZone(), 'MM-dd-yyyy'),inputValue]]);// date string in col A and value in col B in a 2D array (note the S in setValues) -
}