add items into two arrays (future and past dates) based on date - javascript

I am trying to find a way to sort posts into two arrays: upcoming and current (upcoming posts are in the future and current have already been posted).
All posts have a scheduledPubDate that is a date string in the format YYYY-MM-DDT00:00:00. and todays date has to be a Date object as it will need to stay relevent (I am using moment())
Is it possible to compare these two different things without having to use a .split and compare the month / day /year separately
angular.forEach(data.items, function (key, index) {
if (moment(key.scheduledPubDate) > moment()) {
$scope.upcomingPosts.push(item[index]);
} else if (moment(key.scheduledPubDate) <= moment()) {
$scope.currentPosts.push(item[index]);
};
});

Presumably you want the string treated as UTC, a simple parser for that is:
// Expected format YYYY-MM-DDT00:00:00
function parseUTC(s) {
var b = s.split(/\D/);
return new Date(Date.UTC(b[0], b[1]-1, b[2], b[3], b[4], b[5]));
}
Note that this doesn't allow for invalid dates. If needed, an extra line if code is required. So now you can do:
if (parseUTC(key.scheduledPubDate) > new Date()) // or Date.now()
You really don't need moment.js for this.

JavaScript's built-in Date object will help you here.
var date = Date.parse('2014-01-21T12:45:13');
date < Date.now() // true
For the purpose of an example, let's assume items is an array of posts:
var items = [{
scheduledPubDate: '2014-01-21T12:45:13'
// ...other keys here
}, {
scheduledPubDate: '2017-03-01T15:21:00'
} // ...and so on
];
Then a reduce operation over items can categorize the posts:
var posts = items.reduce(function (memo, item) {
memo[Date.parse(item.scheduledPubDate) <= Date.now() ? 'current' : 'upcoming'].push(item);
return memo;
}, { current: [], upcoming: [] });
Now posts.current will contain an array of all posts from items whose scheduledPubDate is before the current date, and posts.upcoming will contain an array of all scheduled posts.
Edited to use Date.parse, to avoid unreliable behavior pointed out by RobG. This requires that all dates be in the YYYY-MM-DDT00:00:00 format you specified; if that is not the case, another solution will be required.

You have to specify the date format of the string
var format = "YYYY-MM-DDT00:00:00";
angular.forEach(data.items, function (key, index) {
if (moment(key.scheduledPubDate, format) > moment()) {
$scope.upcomingPosts.push(item[index]);
} else if (moment(key.scheduledPubDate, format) <= moment()) {
$scope.currentPosts.push(item[index]);
};
});
Working example (See the console.log): http://jsbin.com/fejaxiguce/1/edit?html,output

First create an array of elements, in any order, and then use the .sort() method.
http://www.w3schools.com/jsref/jsref_sort.asp
var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return a-b});
Just substitute the above logic with your own. a and b above can be objects.

Related

How to parse array of date string into Dates in moment

I've a array of dates in a string format.
I wanted to parse the array of dates and pass that new date value into addDates
i tied .format('YYYY-MM-DD'), but not working its give an error Conversion from "undefined" format not allowed on jQuery.multiDatesPicker. Please help
var newDateArray: any[];
"Dates": [
"2018-01-01",
"2018-01-03",
"2018-01-05"
]
for(let i=0; i<= this.newDateArray.length; i++) {
let date = moment(i).format('YYYY-MM-DD');
this.newDateArray.push(i)
}
$(this.eInput).multiDatesPicker({
addDates: [this.newDateArray],
dateFormat: "dd/mm/yy"
});
There are a few issues in your code. Your dates declaration isn't proper javascript, although I'm assuming you copied this from within an object or something. You are also iterating over the empty list rather than your date list and only passing the index in to moment. Change your for loop to this:
var newDateArray: any[];
dates: [
"2018-01-01",
"2018-01-03",
"2018-01-05"
]
// iterate over the dates list from above
for(let i = 0; i <= dates.length; i++) {
// pass the date at index i into moment
let date = moment(dates[i]).format('YYYY-MM-DD');
console.log("date", date);
// add this new date to the newDateArray
this.newDateArray.push(date)
console.log("newDateArray", this.newDateArray);
}

forEach unexpected token adding new property to existing array

I want to add a new proeprrty call total_days calculate using date_from and date_to but my forEach got an expected token error.
let applicants = [{
date_from: '2017-05-05',
date_to: '2017-05-10'
},{
date_from: '2017-05-08',
date_to: '2017-05-12'
}]
calculateDays = applicants.forEach(obj =>
applicants['total_days'] = (obj.date_from).diff(obj.date_to, 'days')+1;
)
No clue what's wrong here.
You didn't exactly clarify what you wanted but I tried to take a guess by your code.
My guess is that you wanted to create a new array of applicants from the old array of applicants but in the new array, you wanted to add a property to each object in that array that is the difference in days of the two dates.
To do so, you can use Array.prototype.map to map each item from your array to a new array.
I'm also using Object.assign to clone each object so that the original array is unmodified.
I'm also parsing the date strings into number. The parsed number is the number of milliseconds elapsed since 1 January 1970 00:00:00 UTC. If I take the difference of the two numbers and divide that be the millisecondsInADay then I'll get how many days elapsed in between.
The result is then stored into a new array calculateDays.
Let me know if you need more clarification.
let applicants = [{
date_from: '2017-05-05',
date_to: '2017-05-10'
}, {
date_from: '2017-05-08',
date_to: '2017-05-12'
}]
const millisecondsInADay = 1000 * 60 * 60 * 24;
const calculateDays = applicants.map(obj => Object.assign({}, obj, {
total_days: ((
Date.parse(obj.date_to) - Date.parse(obj.date_from)
) / millisecondsInADay) + ' days'
}));
console.log(calculateDays);
Assuming you want to add a new property to all objects, you could use obj as variable with a new property.
applicants.forEach(obj => obj.total_days = obj.date_from.diff(obj.date_to, 'days') + 1);
// ^^^

DC.JS Crossfilter - add running cumulative sum

I have defined a table for a portfolio's profit and loss. For each single day the P&L is shown in appropriate DC bar chart, but I want to add a cumulative sum that follows the column date. This should in the example return for End of September only the P&L slice for September, for October the slice for both September and October and so one. If any filter applies in the crossfilter, the applied cumulative sum should apply on filtered data.
*
Date,Cpty,internalRating,ratingSegment,externalRating,Sector,assetClass,riskFactor,riskBucket,sensi,marketMove,PL
30.09.16,DEF,2A,IND,AA,Industrials,IR,EUR,10,-1000,2,-2000
30.09.16,JKL,3B,SERV,BBB,Services,IR,USD,10,-1000,4,-4000
30.09.16,JKL,3B,SERV,BBB,Services,IR,JPY,10,-10000,6,-60000
30.09.16,JKL,3B,SERV,BBB,Services,CS,CDS_JKL,10,-4000,4,-16000
30.09.16,MNO,2B,TRAN,BB,Transportations,IR,EUR,10,1000,-4,-4000
30.09.16,MNO,2B,TRAN,BB,Transportations,CS,CDS_MNO,10,-1000,5,-5000
31.10.16,DEF,2A,IND,AA,Industrials,IR,EUR,10,-1500,6,-9000
31.10.16,JKL,3B,SERV,BBB,Services,IR,USD,10,1500,12,18000
31.10.16,JKL,3B,SERV,BBB,Services,IR,JPY,10,15000,18,270000
31.10.16,JKL,3B,SERV,BBB,Services,CS,CDS_JKL,10,6000,12,72000
31.10.16,MNO,2B,TRAN,BB,Transportations,IR,EUR,10,-1500,-12,18000
31.10.16,MNO,2B,TRAN,BB,Transportations,CS,CDS_MNO,10,1500,15,22500
30.11.16,DEF,2A,IND,AA,Industrials,IR,EUR,10,1428,6,8568
30.11.16,JKL,3B,SERV,BBB,Services,IR,USD,10,1085,12,13020
30.11.16,JKL,3B,SERV,BBB,Services,IR,JPY,10,5046,18,90828
30.11.16,JKL,3B,SERV,BBB,Services,CS,CDS_JKL,10,2579,12,30948
30.11.16,MNO,2B,TRAN,BB,Transportations,IR,EUR,10,-253,-12,3036
30.11.16,MNO,2B,TRAN,BB,Transportations,CS,CDS_MNO,10,409,15,6135
*
Any clue how I can proceed ? Do I need reductio for this ?
Thanks in advance !
As an alternative to #Ethan's clever answer, this is also a great opportunity for a "fake group" (and one of the first documented uses of that technique IIRC).
From the dc.js FAQ:
function accumulate_group(source_group) {
return {
all:function () {
var cumulate = 0;
return source_group.all().map(function(d) {
cumulate += d.value;
return {key:d.key, value:cumulate};
});
}
};
}
Use it like this:
data.forEach(function(r) {
r.Date = dateFormat.parse(r.Date);
});
var cf = crossfilter(data)
var dateDim = cf.dimension(function(d) { return d.Date; });
var plGroup = dateDim.sum(function(d) { return d.PL; });
var accumPLGroup = accumulate_group(plGroup);
If you are using Crossfilter 1.4.0-alpha.06, you can do this using an array dimension. Something like the following:
function getDates(d) {
// This function should return an array of dates or months from
// d.Date until the end of the year.
return [...]
}
var cf = crossfilter(data)
var runningSumDim = cf.dimension(getDates, true)
var runningSumGroup = runningSumDim.sum(function(d) { return d.PL; })
That should "just work" once you work out the logic to derive the array of subsequent months.
What does this do? The dimension accessor should return an array. This array is assumed to be the list of group values that this record should be included in. So you would want the array to include the current month key and the month keys of all subsequent months the record should be included in. Note, this should be an array of subsequent months, not previous months. Somewhat counter-intuitive, but think of it as the answer to the question "What months should this value be counted in?".

JavaScript (Angular) ForEach Loop Changes Not Applying

I have an array of objects with a date formatted in MMMM Do YYYY format. I need to convert this into a UNIX timestamp to arrange them and then convert them back into the readable date format.
However, in doing this. It seems that my changes from within the forEach callback are not applied to the $scope.lalala variable.
My code:
function compare(a, b) {
if (a.date < b.date)
return -1;
if (a.date > b.date)
return 1;
return 0;
}
$scope.lalala = arrayofincompleteorders;
$scope.lalala.forEach(function(hiVanilla, index) {
hiVanilla.date = moment(hiVanilla.date, 'MMMM Do YYYY').format('x');
if (index == $scope.lalala.length - 1) {
$scope.lalala.sort(compare); timestamps as expected
console.log($scope.lalala); //logs the date property with unix
callback();
}
});
console.log($scope.lalala); //logs the date property with unix timestamps, why?
function callback() {
$scope.lalala.forEach(function(order, index) {
console.log(order.date); //unix timestamp
$scope.lalala[index].date = moment(order.date, 'x').format('MMMM Do YYYY');
console.log($scope.lalala[index].date); //formatted timestamp
});
};
Edit: I have the same problem even with the angular.forEach loop in the callback:
function callback(){
angular.forEach($scope.lalala, function(value, key) {
console.log(value.date);
value.date = moment(value.date, 'x').format('MMMM Do YYYY');
console.log($scope.lalala[key].date);
});
console.log("fire!");
$scope.apply();
};
I get the dates to change successfully but then it says that $scope.apply() is not a function which borks the rest of my script.
Edit2:
I got rid of the callback and have everything in one angular.forEach but it still doesn't apply?
$scope.lalala = arrayofincompleteorders;
angular.forEach($scope.lalala, function(hiVanilla, key) {
hiVanilla.date = moment(hiVanilla.date, 'MMMM Do YYYY').format('x');
if (key == $scope.lalala.length - 1) {
$scope.lalala.sort(compare); //timestamps as expected
console.log($scope.lalala); //logs the date property with unix
console.log(hiVanilla.date); //unix timestamp
hiVanilla.date = moment(hiVanilla.date, 'x').format('MMMM Do YYYY');
console.log($scope.lalala[key].date); //formatted timestamp
}
});
console.log($scope.lalala); //logs the date property with unix timestamps, why?
It looks like I was using angular.forEach in a way that it was not designed.
The following worked, basically I just assigned it by pushing it into an empty array rather than trying to alter the array from which I was looping inside of:
$scope.lalala=[];
var log = = arrayofincompleteorders;
angular.forEach(log, function(value, key) {
if(value.complete!="TRUE")
{
i++;
value.date = moment(value.date, 'x').format('MMMM Do YYYY');
this.push(value); //put the new value in $scope.lalala as specified below
}
}, $scope.lalala);

registerEntityTypeCtor initializers does not seem to trigger when using property path expand

I want all Date types in my entities to always be converted to momentjs. The solution (Code 2) I used for this works fine for getResources (Code 1), the initializer is triggered for both the 'Event and 'Shift' entities. But when I call getUser the expand works as it should and I get the right data for both 'Order' and 'Event', but the initializer for 'Event' never triggers. Any ideas why? Is it because I'm using a property path expand?
Also, if you can think of a better solution to convert all Date types in my entities to momentjs I will gladly accept that too.
Code 1:
var getResources = function () {
var query = breeze.EntityQuery
.from("Resources")
.expand("Event, Shift")
.orderBy("ResourceId");
return manager.executeQuery(query)
.fail(fail);
}
var getUser = function () {
var query = breeze.EntityQuery
.from("LoggedInUser")
.expand("Order.Event")
.orderBy("Email");
return manager.executeQuery(query)
.fail(fail);
}
Code 2:
function configureMetadataStore(metadataStore) {
metadataStore.registerEntityTypeCtor('Shift', null, momentInitializer);
metadataStore.registerEntityTypeCtor('Event', null, momentInitializer);
metadataStore.registerEntityTypeCtor('Order', null, momentInitializer);
}
function momentInitializer(entity) {
var newMoment,
prop;
for (prop in entity) {
if (ko.isObservable(entity[prop])) {
if (entity[prop]() instanceof Date) {
newMoment = ko.observable(moment(entity[prop]()));
entity[prop] = newMoment;
}
}
}
}
I am sure there is a better and more detailed answer for this, but from what I understand you are probably trying to display the date in a given format, not actually convert it in the database, correct?
If you are using a binding handler such as Knockout.js you can just change the format in which it is displayed instead of converting the date/time stamp. I am always cautious of converting the dates just to display them because I have had issue in the past with the database getting mad at me for such a thing.
Here is an example of a custom binding handler to show date time as May 29th, 2013, 2:22:00 pm
ko.bindingHandlers.DateTime = {
update: function (element, valueAccessor) {
var value = valueAccessor();
var date = moment(value());
var strDate = date.format('MMMM Do YYYY, h:mm:ss a');
$(element).text(strDate);
}
};

Categories