Error in Date Differences in Google Sheets App Script - google-apps-script

In Googlesheets's "Sheet1", dates are manually entered in Column A.
When I enter a date in column A, Column B should be filled with the difference between new Date() and the date just entered in Column A.
Until now, I have tried the following code:
function onEdit() {
var s2=SpreadsheetApp.getActive().getSheetByName("Sheet1");
var lastRow=s2.getLastRow();
var entry_date =s2.getRange(lastRow, 1).getValue();
var now = new Date();
var diff = now-entry_date;
s2.getRange(lastRow, 2).setValue(diff);
}
However, Column B is giving very random results and I am not being able to understand. I just need the date difference to be filled in column B in the same row.

The result is looking odd to you because you are expecting it in days (the way the sheet would show it) but the script is showing you the result in milliseconds. To get the answer in number-of-days, try this:
function onEdit() {
var s2 = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var lastRow = s2.getLastRow();
var entry_date = s2.getRange(lastRow, 1).getValue();
var now = new Date();
var diff = (now-entry_date) / (24 * 60 * 60 * 1000); // Divide by number of milliseconds in a day
s2.getRange(lastRow, 2).setValue(diff);
}
This will give you an output that looks like 3.4567 (days + fraction of day in milliseconds).
To get it rounded down to just the number of days, you could try this:
function onEdit() {
var s2 = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var lastRow = s2.getLastRow();
var entry_date = s2.getRange(lastRow, 1).getValue();
var now = new Date();
var diff = (now-entry_date) / (24 * 60 * 60 * 1000); // Divide by number of milliseconds in a day
diff = Math.floor(diff); // Round down
s2.getRange(lastRow, 2).setValue(diff);
}

Related

Change the value of a cell if another cell has a date that falls within the current week - apps script

In google sheets I have a task table. Included in the table is a column that has a timeline dropdown and a column that includes a do date. I am trying to change the value of the timeline column if the do date falls within the current week.
For example, using my screenshot below:
Today is 2/7/2023 - I would like to see if the do date falls within this current week (2/5/2023-2/11/2023). Because the do date falls within this week (2/10/2023) I would like the Timeline to change to "This Week"
Here is the code I have tried. I was thinking I could get the first day and last day of the current week, and then compare those two dates to the date listed in the do date column.
function onEdit(event){
var colK = 11; // Column Number of "K"
var changedRange = event.source.getActiveRange();
if (changedRange.getColumn() == colK) {
// An edit has occurred in Column K
//Get this week
var curr = new Date; // get current date
var first = curr.getDate() - curr.getDay(); // First day is the day of the month - the day of the week
var last = first + 6; // last day is the first day + 6
var firstday = new Date(curr.setDate(first)).toUTCString();
var lastday = new Date(curr.setDate(last)).toUTCString();
var doDateTW = new Date(changedRange.getValue.setDate()).toUTCString();
//Set value to dropdown
var group = event.source.getActiveSheet().getRange(changedRange.getRow(), colK - 5);
if (doDateTW >= firstday && doDateTW <= lastday) {
group.setValue("This Week");
}
}
}
In your situation, how about the following modification?
Modified script:
function onEdit(event) {
var { range, source } = event;
var colK = 11;
var changedRange = source.getActiveRange();
if (changedRange.getColumn() == colK) {
var curr = new Date();
var year = curr.getFullYear();
var month = curr.getMonth();
var first = curr.getDate() - curr.getDay();
var last = first + 6;
var firstday = new Date(year, month, first).getTime();
var lastday = new Date(year, month, last).getTime();
var doDateTW = range.getValue().getTime();
var group = source.getActiveSheet().getRange(changedRange.getRow(), colK - 5);
if (doDateTW >= firstday && doDateTW <= lastday) {
group.setValue("This Week");
} else {
group.setValue(null);
}
}
}
When you put a date value to the column "K", when the inputted date value is in this week, "This Week" is put into column "F". When the inputted date value is not in this week, the cell of column "F" is cleared.
In this modification, I used your script of var first = curr.getDate() - curr.getDay(); and var last = first + 6;.

Google Apps Script - Adding/Subtracting Time - Hours/Minutes/Seconds to a particular column in googles sheet

I want to be able to add or subtract Time - Hour/Minutes/Seconds to a particular column with some conditions using google app scripts.
Example - The Image Below.
Column A is the Original Time.
If Column D2 is "Depart To" 30 minutes will be added to the original time (column A2) which will result to the time in Column C2
while If Column D4 is "Arrive from" 30 minutes will be subtracted from the original time (column D2) which will result to the time in Column C4.
which script can I use to achieve this?
Try this:
function myFunction() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var ss = sh.getSheetByName("Sheet1");
var range = ss.getRange(2, 1, ss.getLastRow()-1, 4); //get A2:D4 range
var data = range.getDisplayValues(); //get values
data.forEach(row => { // loop each sub-array returned by getDisplayValues
var time = row[0].split(":"); //split the column a to get hour and minutes
var hour = time[0];
var minutes = time[1];
var fDate = new Date(row[1]) //create new Date object by using column b
fDate.setHours(hour) //set the hour of new Date Object
fDate.setMinutes(minutes) //set the minute of new Date Object
if(row[3].toLowerCase() == "depart to"){
fDate.setMinutes(fDate.getMinutes() + 30); // add 30 minutes to current date object
row[2] = Utilities.formatDate(fDate, Session.getScriptTimeZone(), "H:mm");
}else if(row[3].toLowerCase() == "arrive from"){
fDate.setMinutes(fDate.getMinutes() - 30); // minus 30 minutes to current date object
row[2] = Utilities.formatDate(fDate, Session.getScriptTimeZone(), "H:mm");
}
})
range.setValues(data) //write values to sheet
}
Test Data:
Output:
References:
Date Object
Spreadsheet Class
Range Class
Adding and subtracting dates
function addsubDates() {
const mA = [...Array.from(new Array(12).keys(), x => Utilities.formatDate(new Date(2021, x, 15), Session.getScriptTimeZone(), "MMM"))];//month array
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const vs = sh.getRange(2, 1, sh.getLastRow() - 1, 4).getDisplayValues();//get as string
let vo = vs.map((r, i) => {
let t = r[0].toString().split(':');
let d = r[1].toString().split('-');
let dt = new Date(parseInt(d[2]), mA.indexOf(d[1]), parseInt(d[0]), parseInt(t[0]), parseInt(t[1]));//base date
let a = 0;
if (r[3].toString().toLocaleLowerCase().includes('arrive')) { a = 30; }//adjustments
if (r[3].toString().toLocaleLowerCase().includes('depart')) { a = -30 }
return [Utilities.formatDate(new Date(dt.valueOf() + a * 60000), ss.getSpreadsheetTimeZone(), "HH:mm")];
})
sh.getRange(2, 3, vo.length, vo[0].length).setValues(vo);
}
Data:
21:46
17-Oct-2020
21:16
Depart To
21:47
17-Oct-2020
21:17
Depart To
21:48
17-Oct-2020
22:18
Arrive From
21:49
17-Oct-2020
22:19
Arrive From
21:50
17-Oct-2020
21:20
Depart To
21:51
17-Oct-2020
21:21
Depart To
21:52
17-Oct-2020
22:22
Arrive From
21:53
17-Oct-2020
22:23
Arrive From
Try this formula. Time is hours where 24 hours = 1 so 0.5/24 is a half hour.
=IF(D1="Depart To",A1+(0.5/24),A1-(0.5/24))

How to deal with duplicates in google sheets script?

So in the project I want to do I have a google sheet with timestamps and names next to those timestamps in the spreadsheet. I am having trouble accounting for duplicates and giving the name multiple timestamps in another google sheet.
for(var i = 0; i < length; i++){//for loop 1
if(currentCell.isBlank()){//current cell is blank
daySheet.getRange(i+10, 2).setValue(fullName);//set name to first cell
daySheet.getRange(i+10,3).setValue(pI);
daySheet.getRange(i+10,day+3).setValue(1);
}else if(counter > 1 ){//the index of the duplicate in the sheet month
//if counter is > 1 then write duplicates
for(var t = 1; t <= sheetLength ; t++){//loop through sign in sheet
//current index i
if(signInLN == signInSheet.getRange(t+1,3).getValue()){
//if there is a match
daySheet.getRange(t+10,day+3).setValue(1);
//day is equal to the day I spliced from the timestamp
//at this point I am confused on how to get the second date that has the same
//name and add to the row with the original name.
//when i splice the timestamp based on the row of index i, with duplicates I get
//the day number from the first instance where the name is read
}
}
}//for loop 1
How can I get this to work with duplicates so I can account for the dates but make sure that if there are
any duplicates they will be added to the row of the original name
Google Sheet EX:
12/10/2020 test1
12/11/202 test2
12/15/2020 test1
Should be something like this:
name 10 11 12 13 14 15 16
test1 1 1
test2 1
//the one is to identify that the date is when the user signed in on the sheets.
Sample Spreadsheet:
Code snippet done with Apps Script, adapt it to your needs.
use Logger.log() in case you don't understand parts of code
It is done mainly with functional JavaScript
function main(){
var inputRange = "A2:B";
var sheet = SpreadsheetApp.getActive().getSheets()[0]
var input = sheet.getRange(inputRange).getValues(); //Read data into array
var minDate, maxDate;
var presentDates = input.map(function(row) {return row[0];}); //Turns input into an array of only the element 0 (the date)
minDate = presentDates.reduce(function(a,b) { return a<b?a:b}); //For each value, if its the smallest: keep; otherwise: skip;
maxDate = presentDates.reduce(function(a,b) { return a>b?a:b}); //Same as above, but largest.
var dates = [];
for (var currentDate = minDate; currentDate <= maxDate; currentDate.setDate(currentDate.getDate()+1)) {
dates.push(getFormattedDate(currentDate)); //Insert each unique date from minDate to maxDate (to leave no gaps)
}
var uniqueNames = input.map(function(row) {return row[1];}) //Turns input into an array of only the element at 1 (the names)
.filter(function (value, index, self) {return self.indexOf(value) === index;}); //Removes duplicates from the array (Remove the element if the first appearence of it on the array is not the current element's index)
var output = {}; //Temporary dictionary for easier counting later on.
for (var i=0; i< dates.length; i++) {
var dateKey = dates[i];
for (var userIndex = 0; userIndex <= uniqueNames.length; userIndex++) {
var mapKey = uniqueNames[userIndex]+dateKey; //Match each name with each date
input.map(function(row) {return row[1]+getFormattedDate(row[0])}) //Translate input into name + date (for easier filtering)
.filter(function (row) {return row === mapKey}) //Grab all instances where the same date as dateKey is present for the current name
.forEach(function(row){output[mapKey] = (output[mapKey]||0) + 1;}); //Count them.
}
}
var toInsert = []; //Array that will be outputted into sheets
var firstLine = ['names X Dates'].concat(dates); //Initialize with header (first element is hard-coded)
toInsert.push(firstLine); //Insert header line into output.
uniqueNames.forEach(function(name) {
var newLine = [name];
for (var i=0; i< dates.length; i++) { //For each name + date combination, insert the value from the output dictionary.
var currentDate = dates[i];
newLine.push(output[name+currentDate]||0);
}
toInsert.push(newLine); //Insert into the output.
});
sheet.getRange(1, 5, toInsert.length, toInsert[0].length).setValues(toInsert); //Write the output to the sheet
}
// Returns a date in the format MM/dd/YYYY
function getFormattedDate(date) {
var year = date.getFullYear();
var month = (1 + date.getMonth()).toString();
month = month.length > 1 ? month : '0' + month;
var day = date.getDate().toString();
day = day.length > 1 ? day : '0' + day;
return month + '/' + day + '/' + year;
}
Run script results:

Sum up the time values corresponding to same date

In my sheet column A is date and column B is time duration values, I want to find the dates which are repeated and sum up the corresponding time values of the repeated dates and show the sum in the last relevant repeated date. And delete all the other repeated dates. ie if 18/07/2019 is repeated 4 times i have to sum up all the four duration values and display the sum value in the 4th repeated position and delete the first three date 18/07/2019. I have to do this all those dates that are repeated. I have wrote code to my best knowledge
function countDate() {
var data = SpreadsheetApp.getActive();
var sheet = data.getSheetByName("Sheet5");
var lastRow = sheet.getLastRow();
var sh = sheet.getRange('A1:A'+lastRow);
var cell = sh.getValues();
var data= sheet.getRange('B1:B'+lastRow).getValues();
for (var i =0; i < lastRow; ++i){
var count = 0;
var column2 = cell[i][0];
for (var j =0; j < i; j++)
{
var p=0;
var column4 = cell[j][0];
if (column4 - column2 === 0 )
{
var value1 = data[j][0];
var value2 = data[i][0];
var d = value2;
d.setHours(value1.getHours()+value2.getHours()+0);
d.setMinutes(value1.getMinutes()+value2.getMinutes());
sheet.getRange('C'+(i+1)).setValue(d).setNumberFormat("[hh]:mm:ss");
sheet.deleteRow(j+1-p);
p++;
}
}
}
}
The copy of the sheet is shown
column C is the values I obtain through the above code AND column D is the desired value
After computing the sum I need to delete the repeated rows till 15 here
Answer:
You can do this by converting your B-column to a Plain text format and doing some data handling with a JavaScript dictionary.
Code:
function sumThemAllUp() {
var dict = {};
var lastRow = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getLastRow();
var dates = SpreadsheetApp.getActiveSpreadsheet().getRange('A1:A' + lastRow).getValues();
var times = SpreadsheetApp.getActiveSpreadsheet().getRange('B1:B' + lastRow).getValues();
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).setNumberFormat("#");
for (var i = 0; i < dates.length; i++) {
if (!dict[dates[i][0]]) {
dict[dates[i][0]] = times[i][0];
}
else {
var temp = dict[dates[i][0]];
var hours = parseInt(temp.split(':')[0]);
var minutes = parseInt(temp.split(':')[1]);
var additionalHours = parseInt(times[i][0].split(':')[0]);
var additionalMinutes = parseInt(times[i][0].split(':')[1]);
var newMinutes = minutes + additionalMinutes;
var newHours = hours + additionalHours;
if (newMinutes > 60) {
newHours = newHours + 1;
newMinutes = newMinutes - 60;
}
dict[dates[i][0]] = newHours + ':' + newMinutes;
}
}
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange('A1:B' + lastRow).clear();
var keys = Object.keys(dict);
for (var i = 0; i < keys.length; i++) {
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange('A' + (i + 1)).setValue(keys[i]);
SpreadsheetApp.getActiveSpreadsheet().getSheets()[0].getRange('B' + (i + 1)).setValue(dict[keys[i]]);
}
}
Assumptions I made:
There are a few assumptions I made when writing this, you can edit as needed but I figured I should let you know:
There are only dates in Column A and only times in Column B.
The times in column B are either Hours:Minutes or Minutes:Seconds. Either way, if the value to the right of the : hits 60, it adds one to the left value and resets.
The Sheet within the Spreadsheet is the first sheet; that which is returned by Spreadsheet.getSheets()[0].
References:
w3schools - JavaScript Objects
Spreadsheet.getSheets()
w3schools - JavaScript String split() Method
MDN web docs - parseInt() method
Google Sheets > API v4 - Date and Number Formats

Can't Add More Than One New Trigger to Script Function

I am trying to make both of these new triggers a part of my existing function. I at one time got one to work, and when I added the second, both triggers would not be created at the same time. Help please.
// Trigger every 15 Minutes
ScriptApp.newTrigger('copyPriceData')
.timeBased()
.everyMinutes(2)
.create();
//Delete Trigger after Market Closes
ScriptApp.newTrigger("delete_Triggers")
.timeBased()
.after(6 * 60 * 1000)
.create();
Existing code is:
function CopyLive1() {
var date = new Date();
var day = date.getDay();
var hrs = date.getHours();
var min = date.getMinutes();
if ((hrs >= 15) && (hrs <= 15) && (min >= 46) && (min <= 46)) {
var sheet = SpreadsheetApp.getActiveSheet();
// Get more recent closing prices
var closePriceRange = sheet.getRange("F4");
var prevClosePriceRange = sheet.getRange("F5");
var closePrice = closePriceRange.getValue();
var prevClosePrice = prevClosePriceRange.getValue();
// Check if price data has updated. If so create new row and copy price data.
if (closePrice != prevClosePrice)
{sheet.insertRowsAfter(4, 1);
var rangeToCopy = sheet.getRange("B4:G4");
rangeToCopy.copyTo(sheet.getRange("B5:G5"), {contentsOnly:true});
}
sheet.deleteRow(1825);
}
}