Sorting and filtering on Date Sorting and filtering on Date angularjs angularjs

Sorting and filtering on Date


I think the method you're proposing wouldn't run in to too many performance issues, unless you're going for really old browsers or mobile devices.

I've mocked up an example to do a quick (performance) test. First, I'm defining an object that holds a value optimized for sorting, and a value optimized for display:

var MyDate = function(dateString) {    var date = new Date(dateString);    var displayValue = "{0}.{1}.{2}"        .replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))        .replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))        .replace("{2}", date.getUTCFullYear());    return {        sortKey: date.getTime(),        displayValue: displayValue    };};

The prefixZeroIfNeeded method ensures we get the DD.MM format rather than the dd.mm one:

var prefixZeroIfNeeded = function(nr) {    return nr < 10 ? "0" + nr : "" + nr;};

Then, we need some data to convert:

var data = [];var myDates = data    .map(MyDate)    .sort(function(date1, date2) {        return date1.sortKey - date2.sortKey;    });

Finally, a quick example of a very basic search function:

var searchMyDates = function(str) {    return myDates.filter(function(myDate) {        return myDate.displayValue.indexOf(str) !== -1;    });};

Now, we can create some mockup data and check how long it would actually take to A) map and sort the raw strings to the MyDate objects, and B) search for a string in our collection.

Here's how I generated the raw data:

for (var i = 0; i < 10000; i += 1) {    var y = Math.floor(Math.random() * 101) + 1900;    var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));    var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));    data.push(y + "-" + d + "-" + m);}

Using console.time to measure, processing the data on my machine (A) takes around 40ms. Searching for the string .12. takes around 5-10ms.

Concluding: I think you were definitely on the right track and could continue work in the proposed direction. However, in my personal experience, I've learned that whenever I start work on a feature that involves dates and times, moment.js is the way to go. You'll eventually run in to daylight saving time, time zones, you name it and regret you thought it was simple...

Let me know if this is of any help.

Edit: the code in a snippet (check your browser console for output)

var data = [];var prefixZeroIfNeeded = function(nr) {  return nr < 10 ? "0" + nr : "" + nr;};// Generate random data:for (var i = 0; i < 10000; i += 1) {  var y = Math.floor(Math.random() * 101) + 1900;  var m = prefixZeroIfNeeded(Math.floor(Math.random() * 13));  var d = prefixZeroIfNeeded(Math.floor(Math.random() * 29));  data.push(y + "-" + d + "-" + m);}var MyDate = function(dateString) {  var date = new Date(dateString);  var displayValue = "{0}.{1}.{2}"    .replace("{0}", prefixZeroIfNeeded(date.getUTCDate()))    .replace("{1}", prefixZeroIfNeeded(date.getUTCMonth() + 1))    .replace("{2}", date.getUTCFullYear());  return {    sortKey: date.getTime(),    displayValue: displayValue  };};console.time("Map and sorting");var myDates = data  .map(MyDate)  .sort(function(date1, date2) {    return date1.sortKey - date2.sortKey;  });var searchMyDates = function(str) {  return myDates.filter(function(myDate) {    return myDate.displayValue.indexOf(str) !== -1;  });};console.timeEnd("Map and sorting");console.time("Search");console.log("Searching for the month 12, %d results.", searchMyDates(".12.").length);console.timeEnd("Search");


This may help you a bit. I have used the same thing working with React. Here is a link for Moment.js -http://momentjs.com/docs/#/displaying/format/If you go under Display -> Format on the right menu bar, you'll see localized formats, you will need to use format L - pre defined format from moment which will show you 09/04/1986 (September 4, 1986); otherwise you can create your own using DD-MM-YYYY format.

For Example, The way I used in React for my exercise is

To define a variable using let:let deadlineFormated = Moment(this.props.ToDoItem.deadline).format('llll');

Hope this helps for Angular!


Gist: Decouple sorting and filtering. Do sorting on the internal representation and filtering on the presentation.

Sort on internal representation that is in any naturally sortable format. Your raw YYYY-MM-DD date strings would work, so would parsing them into Date objects. The performance difference could be negligible unless you're dealing with lots and lots of rows -- but in that case you would already have other issues with latency and rendering performance.

It's more intuitive if free-text filtering is done on what's displayed (the presentation). So if you're formatting the dates as "May 7, 2016", do a substring match on that. If you're formatting the dates as DD.MM.YYYY, do a substring match on that.

If filtering is driven by actual date selections from controls like a date picker or a select field, you can do the filtering on the internal representation.