Sort array by ISO 8601 date

JavascriptArraysSortingIso8601

Javascript Problem Overview


how can i sort this array by date (ISO 8601)?

var myArray = new Array();

myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old',    date:'2009-11-25T08:00:00Z' }

Playground:
http://jsfiddle.net/4tUZt/

Thanks in advance!

Javascript Solutions


Solution 1 - Javascript

Sort Lexicographically:

As @kdbanman points out, ISO8601See General principles was designed for lexicographical sort. As such the ISO8601 string representation can be sorted like any other string, and this will give the expected order.

'2007-01-17T08:00:00Z' < '2008-01-17T08:00:00Z' === true

So you would implement:

var myArray = [
    { name:'oldest', date:'2007-01-17T08:00:00Z' },
    { name:'newest', date:'2011-01-28T08:00:00Z' },
    { name:'old',    date:'2009-11-25T08:00:00Z' }
];

myArray.sort(function(a, b) {
    return (a.date < b.date) ? -1 : ((a.date > b.date) ? 1 : 0);
});

Sort using JavaScript Date:

Older versions of WebKit and Internet Explorer do not support ISO 8601 dates, so you have to make a compatible date. It is supported by FireFox, and modern WebKit though See here for more information about Date.parse support https://stackoverflow.com/questions/5802461/javascript-which-browsers-support-parsing-of-iso-8601-date-string-with-date-par

Here is a very good article for creating a Javascript ISO 8601 compatible date, which you can then sort like regular javascript dates.

http://webcloud.se/log/JavaScript-and-ISO-8601/

Date.prototype.setISO8601 = function (string) {
    var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" +
    "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" +
    "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?";
    var d = string.match(new RegExp(regexp));

    var offset = 0;
    var date = new Date(d[1], 0, 1);

    if (d[3]) { date.setMonth(d[3] - 1); }
    if (d[5]) { date.setDate(d[5]); }
    if (d[7]) { date.setHours(d[7]); }
    if (d[8]) { date.setMinutes(d[8]); }
    if (d[10]) { date.setSeconds(d[10]); }
    if (d[12]) { date.setMilliseconds(Number("0." + d[12]) * 1000); }
    if (d[14]) {
        offset = (Number(d[16]) * 60) + Number(d[17]);
        offset *= ((d[15] == '-') ? 1 : -1);
    }

    offset -= date.getTimezoneOffset();
    time = (Number(date) + (offset * 60 * 1000));
    this.setTime(Number(time));
}

Usage:

console.log(myArray.sort(sortByDate));  

function sortByDate( obj1, obj2 ) {
    var date1 = (new Date()).setISO8601(obj1.date);
    var date2 = (new Date()).setISO8601(obj2.date);
    return date2 > date1 ? 1 : -1;
}

Updated usage to include sorting technique credit @nbrooks

Solution 2 - Javascript

You can avoid creating of dates and by using the built–in lexicographic compare function String.prototype.localeCompare, rather than the ?: compound operator or other expressions:

var myArray = [
  {name: 'oldest', date: '2007-01-17T08:00:00Z'},
  {name: 'newest', date: '2011-01-28T08:00:00Z'},
  {name: 'old', date: '2009-11-25T08:00:00Z'}
];

// Oldest first
console.log(
  myArray.sort((a, b) => a.date.localeCompare(b.date))
);

// Newest first
console.log(
  myArray.sort((a, b) => -a.date.localeCompare(b.date))
);

Solution 3 - Javascript

Be careful, the accepted answer now advises to sort our dates lexicographically.

However, this will only work if all your strings use the 'Z' or '+00' timezone (= UTC). Date strings ending with 'Z' do satisfy ISO8601 standard, but all ISO8601 do not end with 'Z'.

Thus, to be fully ISO8601 compliant, you need to parse your strings with some Date library (e.g. Javascript Date or Moment.js), and compare these objects. For this part, you can check Scott's answer that also covers browsers incompatible with ISO8601.

My simple example with Javascript Date (works on any not-too-old browser) :

var myArray = [
    { name:'oldest', date:'2007-01-17T08:00:00Z' },
    { name:'newest', date:'2011-01-28T08:00:00+0100' },
    { name:'old',    date:'2009-11-25T08:00:00-0100' }
];

myArray.sort(function(a, b) {
    return new Date(a.date) - new Date(b.date);
});

Downside : This is slower than just comparing strings lexicographically.

More info about ISO8601 standard : here.

Solution 4 - Javascript

I'd go with this:

const myArray = new Array();

myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old',    date:'2009-11-25T08:00:00Z' }

function byDate (a, b) {
	if (a.date < b.date) return -1; 
	if (a.date > b.date) return 1; 
	return 0;  
}

const newArray = myArray.sort(byDate);


console.clear();
console.dir(myArray);
console.dir(newArray);

Solution 5 - Javascript

http://jsfiddle.net/4tUZt/2/

$(document).ready(function()
{ 
    var myArray = [ { name:'oldest', date:'2007-01-17T08:00:00Z' },
        { name:'newest', date:'2011-01-28T08:00:00Z' },
        { name:'old',    date:'2009-11-25T08:00:00Z' }];
    
    console.log( myArray.sort(sortByDate) );        
});

// Stable, ascending sort (use < for descending)
function sortByDate( obj1, obj2 ) {
    return new Date(obj2.date) > new Date(obj1.date) ? 1 : -1;
}

Solution 6 - Javascript

Demo: http://jsfiddle.net/4tUZt/4/

var myArray = new Array();

myArray[0] = { name:'oldest', date: '2007-01-17T08:00:00Z' };
myArray[1] = { name:'newest', date: '2011-01-28T08:00:00Z' };
myArray[2] = { name:'old',    date: '2009-11-25T08:00:00Z' };

var sortFunction = function (a, b) {
  return Date.parse(b.date) - Date.parse(a.date);
};

/* or

var sortFunction = function (a, b) {
  return new Date(b.date) - new Date(a.date);
};

*/

console.log(myArray.sort(sortFunction));

Solution 7 - Javascript

ISO8601 is designed to sort correctly as plain text, so in general, a normal sort will do.

To sort by a specific key of objects in an array, you need to specify a comparison function to the sort() method. In many other languages, these are easy to write using the cmp function, but JS doesn't have a built in cmp function, so I find it easiest to write my own.

var myArray = new Array();

myArray[0] = { name:'oldest', date:'2007-01-17T08:00:00Z' }
myArray[1] = { name:'newest', date:'2011-01-28T08:00:00Z' }
myArray[2] = { name:'old',    date:'2009-11-25T08:00:00Z' }

// cmp helper function - built in to many other languages
var cmp = function (a, b) {
    return (a > b) ? 1 : ( (a > b) ? -1 : 0 );
}

myArray.sort(function (a,b) { return cmp(a.date, b.date) });

P.s. I would write my array using JSON-like syntax, like this:

var myArray = [
    { name:'oldest', date:'2007-01-17T08:00:00Z' },
    { name:'newest', date:'2011-01-28T08:00:00Z' },
    { name:'old',    date:'2009-11-25T08:00:00Z' }
];

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeterView Question on Stackoverflow
Solution 1 - JavascriptScottView Answer on Stackoverflow
Solution 2 - JavascriptRobGView Answer on Stackoverflow
Solution 3 - JavascripticoumView Answer on Stackoverflow
Solution 4 - JavascriptDziad BorowyView Answer on Stackoverflow
Solution 5 - JavascriptnbrooksView Answer on Stackoverflow
Solution 6 - JavascriptDanil SperanskyView Answer on Stackoverflow
Solution 7 - JavascriptrjmunroView Answer on Stackoverflow