Update a cell every day at a specific time - google-apps-script

To be frank I'm a complete newb at scripting and I have went as far as submitting a request to Googles support and was directed here.
What I'm needing is to be able to update a cell in a spreadsheet every day at a certain time, also I need to be able to do this multiple times daily.
Basically what I need is for is at 8:00 PM I need the values from B4 down to be copied into D4 down. When tried using the basic functions in Google the most that can be obtained is for the minute of 8:00 PM it will update then at 8:00 1 it goes back to 0.
If I hadn't looked for days I wouldn't be asking for help. I apologize for my newbness.
A screenshot of the sheet I'm working with can be found via my Google Drive below.
https://drive.google.com/file/d/0B2GuBHPLz-Z_TWw2ZmtxNWJ0bkU/view?usp=sharing

You need to set up a time-based trigger that runs around 8 PM everyday and it should call the method that will update the cell.
function addTrigger() {
ScriptApp.newTrigger("updateCell").timeBased().atHour(20).everyDays(1).create();
}
function updateCell() {
var url = "<SPREADSHEET URL HERE>";
var cell = "<CELL in A1 Notation>";
SpreadsheetApp.openByUrl(url).getRange(cell).setValue(new Date());
}
You'll have to run the addTrigger method once for setting this up.

Related

Old spreadsheets have wrong time and timezone .getValue() from cell

Problem: wrong time and timezone .getValue() from cell with format time
The bug occurs in old spreadsheets from 2017, but not a spreadsheet from 2022 january or new spreadsheets. update: it did appear in a new sheet as well
What steps will reproduce the problem?
Spreadsheet settings -> timezone GMT+1 (your current timezone)
in cell A1 write 20:00:00
set format cell A1 to "time"
execute this function in google apps script
function showTimeInCellA1() {
const date = SpreadsheetApp.getActiveSheet().getRange("A1").getValue();
SpreadsheetApp.getUi().alert("date in A1 is " + date);
}
Problem: it will alert "date in A1 is Sat Dec 30 1899 19:09:21 GMT+0009"
Expected: I expected time 20:00:00 and GMT+1(because settings spreadsheet are GMT+1)
This appears to be a bug!
Leaving this here for future readers as I think this may have been reported by OP.
There is already a report on Google's Issue Tracker which detail the same kind of behaviour:
wrong time and timezone .getValue() from cell with format time
Google does seem to know about this issue but you can also hit the ☆ next to the issue number in the top left of the page so to let Google know more people are encountering the behaviour so it is more likely to be seen to faster.
A workaround could be to add some years and use the time value of the new date object. I did not examine the exact number of years to be added in order to get valid time information - just tried to get past 1970 which worked for me.
var val2=new Date(val).getTime()+1000*60*60*24*365.25*72 // add ~72 years
Logger.log(new Date(val2))
The value of the current cell in Google Sheets is "8:00:00 AM"
A helper function was used to add the time to a given date:
function utils_buildDate(date,time){
var d=new Date(date);
// +-----------------------------------------------------------------
// | fix time value problem (no date is given in sheet)
// | https://issuetracker.google.com/issues/230650549?pli=1
time=new Date(time).getTime()+1000*60*60*24*365.25*72 // add ~72 years
// +-----------------------------------------------------------------
d.setHours(new Date(time).getHours());
d.setMinutes(new Date(time).getMinutes());
d.setSeconds(new Date(time).getSeconds());
return d;
}

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

Mode set to have the script make calls only every 2 minutes inside the every 1 minute trigger. (Google App 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?

Time value handling on Google Script

I am struggling to understand what is happening within a script I am developing.
The situation is the following: on cell B2 I have inputted 06:45PM, which is automatically taken as time format by GSheets.
On the dummy script, I have the following dummy code:
function whathour() {
var ss=SpreadsheetApp.getActiveSheet();
var t=ss.getRange("B2").getValue();
SpreadsheetApp.getUi().alert(t);
Logger.log(t);
}
(I am using alert as a debug tool, yes).
The amusing result is that the value alerted (or logged) when the function is run is [17-09-14 11:15:25:006 CEST] Sat Dec 30 19:09:05 GMT+00:09 1899. !
I would have focused on the possibility of problematic timezones if I hadnt seen that, well, 18:45 and 19:09 can never be the same time in regards to different timezones!
I am trying to collect just the 18:45 out of the cell in order to do certain time duration operations, but this first step is blocking me. Can anyone help me?
Thanks!
Edit: attached an image of what I described:
How about using getDisplayValue()? This retrieves the displayed value of the cell. The modified script is as follows.
Modified script :
function whathour() {
var ss=SpreadsheetApp.getActiveSheet();
var t=ss.getRange("B2").getDisplayValue();
SpreadsheetApp.getUi().alert(t);
Logger.log(t);
}

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