How to Sort Date and/or Time in JavaScript

Robbie Brandrick | 7/23/2013 7:10:22 PM

Introduction

I have recently been working on a JavaScript project where I needed to sort Dates by descending order and Time by ascending order. For this project, I am already using Moment.js as my Date Time JavaScript Library. The aggregate I am sorting contains moment objects and not native Date JavaScript objects.

Sorting by the JavaScript Date object is easy enough, but I have not found many methods on sorting by Date and Time independently. Therefore, the goal of this post is to come up with a solution for sorting by descending Date and ascending Time.

Sort by Date

In JavaScript, sorting by Date and Time in either ascending or descending order is pretty much built in through the Date’s greater then ( > ) and less then ( < ) operators.

Example 1:

var 
	//MomentJs Objects to Sort
	momentDates = […],
	//Sort Date By Ascending Order Algorithm            
	sortByDateAsc = function (lhs, rhs)  { return lhs > rhs ? 1 : lhs < rhs ? -1 : 0; },
	//Sort Date By Descending Order Algorithm
	sortByDateDesc = function (lhs, rhs) { return lhs < rhs ? 1 : lhs > rhs ? -1 : 0; },
	
//Sort Date By Ascending Order 
momentDates.sort(sortByDateAsc);
//Sort Date By Descending Order
momentDates.sort(sortByDateDesc);

Sort by Time

With JavaScript alone, I have not found a quick and easy solution to sort specifically by time; therefore, we need to create one.

I am going to breakdown the hours, minutes and seconds then compare them individually. I am going to start with comparing hours first and only if the hours are identically I will compare minutes. If minutes are identical, I will finally compare seconds. One could easily go as precise as milliseconds, but that level of accuracy is not necessary for my needs.

Example 2:

var
            sortByTimeAsc = function (lhs, rhs)  {
                var results;
 
                results = lhs.hours() > rhs.hours() ? 1 : lhs.hours() < rhs.hours() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.minutes() > rhs.minutes() ? 1 : lhs.minutes() < rhs.minutes() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.seconds() > rhs.seconds() ? 1 : lhs.seconds() < rhs.seconds() ? -1 : 0;
 
                return results;
            },
            sortByTimeDesc = function (lhs, rhs) {
                var results;
results = lhs.hours() < rhs.hours() ? 1 : lhs.hours() > rhs.hours() ? -1 : 0; if (results === 0) results = lhs.minutes() < rhs.minutes() ? 1 : lhs.minutes() > rhs.minutes() ? -1 : 0; if (results === 0) results = lhs.seconds() < rhs.seconds() ? 1 : lhs.seconds() > rhs.seconds() ? -1 : 0; return results; }; //Sort Only Time by Ascending Order momentDates.sort(sortByTimeAsc); //Sort Only Time by Descending Order momentDates.sort(sortByTimeDesc);

Sort by Descending Date and Ascending Time

It would be nice to simply combine both of these algorithms into a nice easy to use function:

Example 3

            sortByDateDescAndTimeAsc = function (lhs, rhs) {
                var results = sortByDateDesc(lhs,rhs);
 
                if (results === 0)
                    results = sortByTimeDesc(lhs, rhs);
                
                return results;
            }, 

Unfortunately, as I previously stated the greater then ( > ) and less then ( < ) operators sort by Date and Time; Therefore, this approach would not work because sortByDateDesc would only ever return “0” if both of the Date and Time are identical, effectively bypassing or uselessly executing the Time sorting portion of the code. 

 

I have decided we could segregate the Date portion into Years, Months and Days, similarly to how we sorted Times (e.g., If the Years, Months and Days are identical then compare the Time portion as we previously did).

Example 4

            sortByDateDescAndTimeAsc = function (lhs, rhs) {
                var results;
 
                results = lhs.years() < rhs.years() ? 1 : lhs.years() > rhs.years() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.months() < rhs.months() ? 1 : lhs.months() > rhs.months() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.date() < rhs.date() ? 1 : lhs.date() > rhs.date() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.hours() > rhs.hours() ? 1 : lhs.hours() < rhs.hours() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.minutes() > rhs.minutes() ? 1 : lhs.minutes() < rhs.minutes() ? -1 : 0;
 
                if (results === 0)
                    results = lhs.seconds() > rhs.seconds() ? 1 : lhs.seconds() < rhs.seconds() ? -1 : 0;
 
                return results;
            }, 

Conclusion

By breaking down this problem, we were easily able to create a solution that works. But, I know I know you are not using Moment.js and you don’t want to use Moment.js just to sort Dates. Well, Moment.js is simply a wrapper, with amazing features, around a native Date object. You can easily alter my provided examples and use the Date object to accomplish the exact same thing. The only difference, for example,  is instead of invoking the method seconds on a moment.js object, you would invoke getSeconds on a Date object.

To quickly generate the native JavaScript code, skillfully write a macro to find and replace the Date object’s getters (I.E. Find: hs. Replace: hs.get), capitalize the method names and make a couple other small tweaks.

Example 5:

                sortByDateDescAndTimeAscDateObj = function (lhs, rhs) {
                    var results;
 
                    results = lhs.getYear() < rhs.getYear() ? 1 : lhs.getYear() > rhs.getYear() ? -1 : 0;
 
                    if (results === 0)
                        results = lhs.getMonth() < rhs.getMonth() ? 1 : lhs.getMonth() > rhs.getMonth() ? -1 : 0;
 
                    if (results === 0)
                        results = lhs.getDate() < rhs.getDate() ? 1 : lhs.getDate() > rhs.getDate() ? -1 : 0;
 
                    if (results === 0)
                        results = lhs.getHours() > rhs.getHours() ? 1 : lhs.getHours() < rhs.getHours() ? -1 : 0;
 
                    if (results === 0)
                        results = lhs.getMinutes() > rhs.getMinutes() ? 1 : lhs.getMinutes() < rhs.getMinutes() ? -1 : 0;
 
                    if (results === 0)
                        results = lhs.getSeconds() > rhs.getSeconds() ? 1 : lhs.getSeconds() < rhs.getSeconds() ? -1 : 0;
 
                    return results;
                },

I hope this can be of value to someone. You can find another example of the code here:

Leave a comment!

But, you have to sign in first!