Javascript - create array between two date objects - javascript

Question
I am attempting to build an array between two JS objects. It appears that my objects are being created correctly, and in fact that the code below is running.
The unexpected behavior is that every object in my output array is transforming to match the last date that I looped through. i.e. if I loop, whatever my todate_dateobjis, I get an entire array of just that value.
I have to do some debugging wrt the actual start/end dates being correct, but I can handle that -- what I'm stymied by is the behavior described above.
I am very new to javascript. I imagine this is some issue with mutation? Any guidance would be appreciated.
I left the console logs in just because why take them out?
Code
function build_dateobjs_array(fromdate_dateobj, todate_dateobj) {
// return an array of dateojects from fromdate to todate
var current_date = fromdate_dateobj;
var return_array = []
while (current_date <= todate_dateobj) {
return_array[return_array.length] = current_date; // I have read that this is generally faster that arr.push()
var tomorrow = new Date(current_date.getTime() + 86400000);
console.log('tomorrow: ', tomorrow);
current_date.setTime(tomorrow);
console.log('current_date: ', current_date)
console.log("build_dateobjs_array : ", return_array);
};
return return_array;
};

Date objects are mutable. This line:
current_date.setTime(tomorrow);
...changes the state of the Date object that current_date refers to, which you never change.
So you're storing the same object repeatedly in return_array. Instead, make a copy of the Date:
return_array[return_array.length] = new Date(+current_date);
Also, it's probably best to change
var current_date = fromdate_dateobj;
to
var current_date = new Date(+fromdate_dateobj);
so you're not modifying the Date that was passed in.
Side note: There's no need for the round-trip to milliseconds, simply:
function build_dateobjs_array(fromdate_dateobj, todate_dateobj) {
// return an array of dateojects from fromdate to todate
var current_date = new Date(+fromdate_dateobj);
var return_array = [];
while (current_date <= todate_dateobj) {
return_array[return_array.length] = new Date(+current_date);
current_date.setDate(current_date.getDate() + 1);
};
return return_array;
}
(There's also no reason to put a ; at the end of a function declaration.)

Related

js find min difference in date array

I have a sorted array:
[new Date('2017-01-02'), new Date('2017-01-07'), new Date('2017-01-09'), new Date('2017-01-17')]
Now I want to find the minimum time difference occuring in the array between any two adjacent elements. eg in this case:
new Date('2017-01-09').getTime() - new Date('2017-01-07').getTime()
is there some elegant way with map or something similar or do I have to loop, remember the smalles interval so far and then replace the value if a smaller one occurs?
Current solution:
let timestamps = Gps.find().map(doc => doc.timestamp);
timestamps.sort();
let minimumDifference;
let previousTimestamp;
timestamps.forEach(timestamp => {
if(!previousTimestamp) {
previousTimestamp = timestamp;
}
else{
let difference = timestamp.getTime() - previousTimestamp.getTime();
if(!minimumDifference || minimumDifference > difference){
minimumDifference = difference;
}
previousTimestamp = timestamp;
}
});
I would like to go back into olden days. plain old javascript. Not creating unnecessory copy
var timestamps = [1,2,5,9];
timestamps.sort();
var result = timestamps[timestamps.length-1];
for(var i=1;i<timestamps.length;i++){
result = (timestamps[i]-timestamps[i-1])<result?(timestamps[i]-timestamps[i-1]):result;
}
take mills and proceed same way

Why does this Javascript function not work if called twice?

The Jasmine (unit?) tests I'm running works for all test with my code below, but the last test calls Gigasecond.date() twice, then validates the second one, which fails.
var Gigasecond = function(date) {
this.startDate = date;
};
Gigasecond.prototype.date = function() {
var x = this.startDate;
x.setSeconds(x.getSeconds() + 1000000000);
return x;
}
module.exports = Gigasecond;
I guess I don't know why this fails. When I log to the console I see the date gets incremented twice, but thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object? Is there any reference material for how this works? I looked around but couldn't find anything that applies to what's happening in this code.
You state that you
thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object?
That is correct. Dates are objects, and in JavaScript, objects are assigned to variables by reference, not copy. If you intend to work with a copy, you need to return a clone of the Date object with new Date(dateToBeCopied.getTime()) first.
In your code, if you want to work on a copy of the date, you need to replace the line
var x = this.startDate; //assignment by reference
with this line
var x = new Date(this.startDate.getTime()); //assignment by copy
The example code below demonstrates how this works. The Date Object dateA is assigned to the variable refA by reference and to the variable copyA by copy. When modifying refA, this affects dateA, whereas copyA is unaffected.
var dateA = new Date();
//assign a reference to dateA
var refA = dateA;
//assign a copy of dateA
var copyA = new Date(dateA.getTime());
//modify refA, increment with one year
refA.setFullYear(refA.getFullYear() + 1);
//variable refA points to dateA,
//both show the date incremented with one year
console.log('+1 year: ', dateA);
console.log('+1 year: ', refA);
//variable copyA returns an unmodified copy,
//not incremented
console.log('unmodified copy: ', copyA);

Javascript in Zapier to return multiple values for posting to Airtable database

I am trying to write some javascript in Zapier which will read two dates and then return an array of all dates between those dates in such a way that they can then be used to create multiple dated records in Airtable (a database). From the Zapier help it says that if you return an array of objects then the following steps will be processed for each.
I have managed to get code which returns the data I wan but it can't be correct because if I try to create the database records only one is created - with all the dates in (so it will only work if output to a text field - not a date). Here's my code attempt:
var fromDate = new Date(inputData.from);
var toDate = new Date(inputData.to);
var output =[];
var i = 1;
do {
var useDate = new String(fromDate.toISOString())
output.push(useDate);
console.log(fromDate);
fromDate.setDate(fromDate.getDate() + 1);
i++
}
while (fromDate <= toDate);
console.log(output);
return{output};
The subsequent step does see the output variable - but it is treated as one value as I said above.
Does anyone have any ideas?
Thanks Juan
That sorted it - or at least it did after removing the return - here is the working code:
var fromDate = new Date(inputData.from);
var toDate = new Date(inputData.to);
var output =[];
var i = 1;
do {
var useDate = new String(fromDate.toISOString())
var dateObject = {};
dateObject.date = useDate;
output.push({dateObject});
fromDate.setDate(fromDate.getDate() + 1);
i++
}
while (fromDate <= toDate);
It looks like you're returning an object, not an array of objects:
return{output};
Also, your do/while statement is creating an array of strings, not objects. In your do block, instead of pushing the useDate string to the output array, you should construct a simple object and push that to the output array.
So instead of pushing '2016-09-28T00:00:00.000Z' each time the loop runs, you should push something like {date: '2016-09-28T00:00:00.000Z'}.
Your do block should look something like this:
do {
var useDate = new String(fromDate.toISOString());
var dateObject = {};
dateObject.date = useDate;
output.push(dateObject);
fromDate.setDate(fromDate.getDate() + 1);
i++
}
This way, output will be an array of objects:
[
{
"date": "2016-09-28T00:00:00.000Z"
},
{
"date": "2016-09-29T00:00:00.000Z"
},
{
"date": "2016-09-30T00:00:00.000Z"
}
]

Javascript push keeps deleting first item

I have very strange problem. I am creating an array of date objects (mondays)
// array to hold week commencing dates
var mondays = [];
mondays.push(today);
var novi = new Date(today);
while(novi < endDate){
var next_monday = new Date(novi.setDate(novi.getDate() + 7));
day_index = next_monday.getDay();
if(day_index == 1){
mondays.push(next_monday);
}
// increment the date
novi = next_monday;
}
console.log(mondays);
UPDATE: Thanks for reply. I created new object at start and used that one.So again i am creating empty array, then adding one date to it before starting loop, then first item in loop doesnt get added, even tho it gets pushed. What am i doing wrong?
This is console.log that i am getting from above.
https://www.dropbox.com/s/04bckfcrwl7yvwd/Screenshot%202016-09-28%2018.29.25.png?dl=0
today.setDate(today.getDate() + 7)
You are modifying the date object you pushed into the array.
The first item isn't being deleted, it is being changed.
var next_monday = new Date(today.setDate(today.getDate() + 7));
Then you create a new date object from it.
Create the new date object first, then modify that.

Sorting an array in javascript based on date

I'm trying to parse multiple subreddit feeds in a Google Script. I can call this Google Script (redditFeeds()) and it returns the title, link, and date to my spreadsheet. However, I want to sort the posts by date so I can see the most recent posts first. I've tried using sort() on the array in various ways and can't get anything sort by descending date. I've even tried converting the date to a Date object and that didn't fix it.
function redditFeeds() {
var entries_array = [];
var subreddit_array = ['https://www.reddit.com/r/funny/top/.rss','https://www.reddit.com/r/news/top/.rss']
for (var s = 0; s < subreddit_array.length; s++) {
var xml = UrlFetchApp.fetch(subreddit_array[s]).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');
var entries = document.getRootElement().getChildren('entry', atom);
for (var i = 0; i < entries.length; i++) {
var title = entries[i].getChild('title', atom).getText();
var title = entries[i].getChild('link', atom).getText();
var link = entries[i].getChild('link', atom).getAttribute('href').getValue();
var date = entries[i].getChild('updated', atom).getValue();
entries_array.push([title, link, date]);
}
}
//return entries_array;
//doesn't work
//entries_array.sort(function(a,b) {
// return a.date - b.date;
//});
//also not working
return entries_array.sort(function(a,b) {
new Date(a.date).getTime() - new Date(b.date).getTime();
});
}
I think you want the below, assuming entries_array looks like I think it does. I have no idea what start was supposed to be in your code... I think each entry in entries_array is an array with three members in it, the third being some sort of representation of a date. If it's one that can be parsed by new Date, then this code should work:
return entries_array.sort(function (a, b) {
return new Date(a[2]) - new Date(b[2]);
});
If that's not right, please share what entries_array looks like.
I see a return missing, in the inner sort function and you should not need the getTime()
return entries_array.sort(function(a,b) {
return new Date(a.start) - new Date(b.start);
});
An easy way of sorting date objects is by converting them into UNIX time stamps using dateObj.getTime(). This creates an integer of the seconds since midnight on New Years day 1970. It's very useful if you are working in multiple time zones.

Categories

Resources