Javascript docs sheets object comparison - javascript

I cant compare javascript object to string, I'm using Google Sheets JavaScript. Data is date but when I checked it with typeof it indicated object. Here is my code:
function myFunction() {
SpreadsheetApp.getUi()
.alert('Running My Function');
}
function myFunction() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getSheetByName("Taulukko1");
var values = sheet.getRange("A1:K28").getValues();
var row_del = new Array();
for(var i=0;i<values.length; i++)
{
if(new Date(values[i][7]).getDate() == new Date('2020-09-17').getDate()){
row_del.push(i);
}
}
for (var i = row_del.length - 1; i>=0; i--) {
sheet.deleteRow(row_del[i]); }
}

A date is an object.
However, you cannot compare dates directly.
To compare dates, the easiest is to convert them to milliseconds.
Sample:
if(new Date(values[i][7]).getTime() == new Date('2020-09-17').getTime()){
// do something
}
note the correct formatting.
References:
new Date()
getTime()

Related

Return index of matched array not working - Javascript Google Apps Script

I have a spreadsheet and row #1 has dates in each cell going across
I want to return the column number whenever that column matches today's date. First header starts in cell B1.
I am using the following and I can get it to work, but when instead I do 'return i', it always returns '0'.
function getColumnIndex() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getValues(); //create an array of data from row 1
for (var i = 0; i <= data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
if (data[i] == dateToday) {break};
{
return i;
}
}
}
Now if I switch the last line 'return i' to 'return dateToday' the function will work and it will return the correct date so I know it's matching properly (and if I change row cells to other values it will return those values if it matches). I just can't get it to spit out the index number when I put 'return i'.
Issues / Explanation:
var data = sheet.getRange(1,2,1,lastColumn).getValues(); returns a 2D array.
As a result, data[i] returns a 1D array which is actually referring to the row. To solve this issue, flatten the array to convert it to 1D:
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat();
Your if condition is executed at the first iteration i=0 because you put a semicolon ; right after it. Also, break is not needed because nothing will be executed after the return statement:
Replace:
if (data[i] == dateToday) {break};
{
return i;
}
with
if (data[i] == dateToday)
{
return i;
}
When you are working with date comparisons, you need to use getDisplayValues() to be sure that you are comparing the the displayed values
and not the value of the date.
Solution:
function getColumnIndex() {
var spreadsheet = SpreadsheetApp.getActive();
var sheet = spreadsheet.getActiveSheet();
var lastColumn = sheet.getLastColumn();
var data = sheet.getRange(1,2,1,lastColumn).getDisplayValues().flat(); //create an array of data from row 1
for (var i = 0; i <= data.length; i++) {
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
if (data[i] == dateToday)
{
return i;
// return i+2; // if you want to get the column number instead.
}
}
}
Keep in mind, i refers to the position of the array. In JavaScript, the indexes in the arrays start from 0. Also, your data starts from the second column. If you want your script to return the number of column, then change return i to return i+2.
function getColumnIndexForToday() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getActiveSheet();
const shsc=2;
const offset=0;//0 if you want the index from column B 1 if you want the index from ColumnA
const data=sh.getRange(1,shsc,1,sh.getLastColumn()-shsc+1).getDisplayValues()[0];//assuming format is "MM/dd/yyyy"
var dObj={};
data.forEach(function(h,i){dObj[h]=i+offset;});//You really can just do this once and then use it repeatedly
var dateToday = Utilities.formatDate(new Date(), "EST", "MM/dd/yyyy")
return dObj[Utilities.formatDate(new Date(),Session.getScriptTimeZone(),"MM/dd/yyyy")];
}

Declaring Global Array in Google Spreadsheet

I am trying speedup the processing/calculation in Google spreadsheet by putting my bonus setting into global array using PropertiesServices instead of loading the bonus % from the Setting sheet whenever user update their Daily sheet.
The method I used seem not working as I expected, the FOR loop is unable to look for "ALL". Hope someone able to give some advice.
I suspected that JSON structure is different from my 2D array, but I don't know how to solve it, I am new to javascripts.
Setting sheet only containing 4 columns: Game, StartDate, EndDate, Bonus %
p/s: This is a simplified scripts.
function onOpen(event) {
var bonusSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setting");
var bonusCompany = bonusSheet.getRange("A46:D503").getValues();
PropertiesService.getDocumentProperties().setProperty("bonusCompany", JSON.stringify(bonusCompany));
}
function onEdit(event) {
var colGame = "H";
var colBonus = "K";
var numColBonus = 11;
var nPoint;
var sheet = event.source.getActiveSheet();
var row = sheet.getActiveCell().getRow();
var col = sheet.getActiveCell().getColumn();
var cGame = sheet.getRange(colGame+row).getValue();
var dDate = new Date();
for(var k=0, kLen=bonusCompany.length; k<kLen; k++)
{
if((bonusCompany[k][0] == cGame || bonusCompany[k][0] == "ALL") && dDate.valueOf() >= bonusCompany[k][1] && dDate.valueOf() <= bonusCompany[k][2] ){
sheet.getRange(event.range.rowStart,numColBonus,event.range.rowEnd-event.range.rowStart+1,1).setValue(nPoint*bonusCompany[i][4]/100);
return;}
}
sheet.getRange(event.range.rowStart,numColBonus,event.range.rowEnd-event.range.rowStart+1,1).setValue(0);
}
If you want to use PropertiesService.getDocumentProperties(), how about following sample script?
Your script is almost correct. When the data is set by PropertiesService.getDocumentProperties().setProperty(), the data can be retrieved by PropertiesService.getDocumentProperties().getProperty(). The detail information is https://developers.google.com/apps-script/reference/properties/properties-service.
And when the array data is set by setProperty(), the array data is stored as strings by JSON.stringify(). So it is necessary to convert from the string data to the array data. Fortunately, it has already known that the values retrieved by getValues() from spreadsheet is 2 dimensional array. So the string data can be converted to an array data using the regular expression. The sample script is as follows. I added 2 lines to your script. Please check them.
Script :
function onOpen(event) {
var bonusSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Setting");
var bonusCompany = bonusSheet.getRange("A46:D503").getValues();
PropertiesService.getDocumentProperties().setProperty("bonusCompany", JSON.stringify(bonusCompany));
}
function onEdit(event) {
var colGame = "H";
var colBonus = "K";
var numColBonus = 11;
var nPoint;
var sheet = event.source.getActiveSheet();
var row = sheet.getActiveCell().getRow();
var col = sheet.getActiveCell().getColumn();
var cGame = sheet.getRange(colGame+row).getValue();
var dDate = new Date();
var d = PropertiesService.getDocumentProperties().getProperty("bonusCompany").split(/^\[|\]$/)[1].split(/\[(.*?)\]/); // I added this line.
var bonusCompany = [[(e=="\"\"" ? "" : e) for each (e in f)] for each (f in [d[j].split(",") for (j in d) if(j%2==1)])]; // I added this line.
for(var k=0, kLen=bonusCompany.length; k<kLen; k++) {
if((bonusCompany[k][0] == cGame || bonusCompany[k][0] == "ALL") && dDate.valueOf() >= bonusCompany[k][1] && dDate.valueOf() <= bonusCompany[k][2] ){
sheet.getRange(event.range.rowStart,numColBonus,event.range.rowEnd-event.range.rowStart+1,1).setValue(nPoint*bonusCompany[i][4]/100);
return;
}
}
sheet.getRange(event.range.rowStart,numColBonus,event.range.rowEnd-event.range.rowStart+1,1).setValue(0);
}
I don't know data of your spreadsheet. So if this modification doesn't work, can I ask you about the data of your spreadsheet?

Using javascript create inner array group by month and year

I have an array look like:
var v = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"]
What I want to do is sort this dynamically into a new empty array nv. When the sorting is done nv should look like.
var nv = [["07/27/2015", "07/28/2015"], ["08/29/2015", "08/29/2015"], ["07/27/2016"]]
Is it possible to sort like this way?
var dates = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"];
var groupedDates = dates.reduce(function(l, r) {
var keyParts = r.split("/"),
key = keyParts[2] + keyParts[0];
if (typeof l[key] === "undefined") {
l[key] = [];
}
l[key].push(r);
return l;
}, {});
var result = Object.keys(groupedDates)
.sort(function(a, b) { return Number(a) - Number(b); })
.map(function(key) {
return groupedDates[key];
});
console.log(result); // [["07/27/2015","07/28/2015"],["08/29/2015","08/29/2015"],["07/27/2016"]]
fiddle
So I made a function that puts the dates into an object whose properties are month and year. A date is put into the property of its month and year. The function then creates an array and creates an inner array for every property of the function. In each inner array it puts all the dates of that property. I figured this approach would be more efficient than nested for loops.
// function takes an array of dates in the following format MM/DD/YYYY
// outputs an array with inner arrays of dates. Each inner array contains dates of the same month and year
var groupDates = function(dateArray) {
// create object to organize dates by month and year
var dateHash = {};
// the array that is outputted
var groupedDates = [];
//for every date in dateArray
dateArray.forEach(function(currentDate) {
// check if any other dates with the same month and year exist in the dateHash object
if (dateHash[currentDate.substr(0, 2) + currentDate.substr(6)]) {
// if other dates exist, push the date to the array in the dateHash property for the dates current month and year
dateHash[currentDate.substr(0, 2) + currentDate.substr(6)].push(currentDate);
} else {
// otherwise create a property for the dates month and year and store the current date in an array in the propery
dateHash[currentDate.substr(0, 2) + currentDate.substr(6)] = [currentDate];
}
});
// for every propery in the datehash, push the array of dates into the grouped dates array
for (var dateGroup in dateHash) {
groupedDates.push(dateHash[dateGroup]);
}
return groupedDates;
};
var dateArray = ["07/27/2015", "07/28/2015", "08/29/2015", "08/29/2015", "07/27/2016"];
console.log(groupDates(dateArray));
You can loop over the array and check for each value if it has a new month and year, or it's already included in the sorted array. I think like this untested code:
new_arr = new Array();
for(var i=0; i < v.length; i++){
var this_date = new Date(v[i]);
var month_and_year = this_date.getMonth() + this_date.getFullYear();
if(typeof(new_arr[month_and_year]) == 'undefined'){
new_arr[month_and_year] = new Array();
}
new_arr[month_and_year].push(v[i])
}

moment.js isAfter performance

I have my dates converted to moment.js, and now I want to compare it with another date ('now' in this case).
Just a plain compare with a date object seems to be a lot faster than using moment.js isAfter function.
Will this simple compare work in all locales?
Am I missing something here?
Is there a very specific reason why isAfter seems to create a new moment object instead of taking a shortcut when it's a Date object?
All my dates are in UTC.
function executeTests() {
isAfterTest();
compareTest();
}
function isAfterTest() {
console.time('isAfterTest');
var now = new Date();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth.isAfter(now);
}
console.timeEnd('isAfterTest');
}
function compareTest() {
console.time('compareTest');
var now = new Date();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth > now;
}
console.timeEnd('compareTest');
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment-with-langs.js"></script>
<button onclick="executeTests();">Run Test</button>
Results:
isAfterTest: 3754.000ms (index):32
compareTest: 24.000ms
See: http://jsfiddle.net/t4grs0p7/2/
Looking at the documentation http://momentjs.com/docs/ the isAfter method accepts different types of Date format:
moment().isAfter(Moment|String|Number|Date|Array);
This means it needs to do type checking and then convert it to a date object before running the calculation.
One way you could reduce this impact would be to pass in a Moment object as the comparison date:
function isAfterTest() {
console.time('isAfterTest');
var now = moment();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth.isAfter(now);
}
console.timeEnd('isAfterTest');
}
I created a fiddle to compare, but that doesn't seem to improve it much at all:
http://jsfiddle.net/kmturley/t4grs0p7/7/
Looking at your version I believe you should be using valueOf() method to compare the values:
window.compareTest2 = function() {
console.time('compareTest2');
var now = moment().valueOf();
var dateOfBirth = moment('2000-01-01').valueOf();
for ( var i = 0; i < 50000; i++ )
var x = dateOfBirth > now;
console.timeEnd('compareTest2');
}
Here is a working example:
http://jsfiddle.net/kmturley/t4grs0p7/8/

Insert more than 250 items in sharepoint list using javascript

I am not able to add 365 days( date format: 01/01/2014) of year in a sharepoint list using javascript.
but it is updating list when I enter range of 'for' loop = 250.
Please refer below code.
function DateIncrement() {
var siteUrl = '/sites/..';
var clientContext = new SP.ClientContext(siteUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Student');
var itemCreateInfo = new SP.ListItemCreationInformation();
for (i = 1; i < 365; i++) {
var myDate = new Date("01/01/2014");
myDate.setDate(myDate.getDate() + i);
var str = myDate;
this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Date', str);
oListItem.update();
}
clientContext.load(oListItem);
clientContext.executeQueryAsync(onSucceededCallback, onFailedCallback);
function onSucceededCallback(sender, args) {
alert("Complete");
}
function onFailedCallback(sender, args) {
alert("Failed");
}
}
The date must be specially formatted. In SharepointPlus I created a function that converts a JavaScript Date to the Sharepoint format.
The format should be: "year-month-day hours:minutes:seconds". So, for "31/Oct/2012" it must be "2012-10-31 00:00:00".
The function toSPDate looks like that:
function toSPDate(oDate) {
var pad = function(p_str){
if(p_str.toString().length==1){p_str = '0' + p_str;}
return p_str;
};
var month = pad(oDate.getMonth()+1);
var day = pad(oDate.getDate());
var year = oDate.getFullYear();
var hours = pad(oDate.getHours());
var minutes = pad(oDate.getMinutes());
var seconds = pad(oDate.getSeconds());
return year+"-"+month+"-"+day+" "+hours+":"+minutes+":"+seconds;
}
Note: SharepointPlus uses the Sharepoint web services. I'm not sure if you need to do the same with the Microsoft native functions.
Note 2: I read again your question but I'm not sure I understood correctly... If not, please try to explain again your issue.

Categories

Resources