1227

Say I have an array of a few objects:

var array = [{id: 1, date: Mar 12 2012 10:00:00 AM}, {id: 2, date: Mar 8 2012 08:00:00 AM}];

How can I sort this array by the date element in order from the date closest to the current date and time down? Keep in mind that the array may have many objects, but for the sake of simplicity I used 2.

Would I use the sort function and a custom comparator?

leonheess
  • 16,068
  • 14
  • 77
  • 112
ryandlf
  • 27,155
  • 37
  • 106
  • 162
  • If you use Date constructor, check this first https://stackoverflow.com/questions/5619202/converting-a-string-to-a-date-in-javascript – ohkts11 Aug 17 '19 at 09:06
  • 2
    the quickest way is to use the isomorphic [sort-array](https://github.com/75lb/sort-array) module which works natively in both browser and node, supporting any type of input, computed fields and custom sort orders. – Lloyd Oct 21 '19 at 20:28
  • 3
    It seems like this question hasn't been answered. None of the answers below explain how to " order from the date closest to the current date". – d13 Nov 18 '21 at 16:15
  • not directly related, but if someone is trying to sort data fetched from a DB, this should be done in the SQL query. – Fed Oct 08 '22 at 12:28
  • @Fed No it shouldn't. That depends entirely on the situation. There are plenty of situations where sorting on the client makes sense even if this particular piece of data comes from a database. – glennsl Jun 26 '23 at 14:05

24 Answers24

2151

Simplest Answer

array.sort(function(a,b){
  // Turn your strings into dates, and then subtract them
  // to get a value that is either negative, positive, or zero.
  return new Date(b.date) - new Date(a.date);
});

More Generic Answer

array.sort(function(o1,o2){
  if (sort_o1_before_o2)    return -1;
  else if(sort_o1_after_o2) return  1;
  else                      return  0;
});

Or more tersely:

array.sort(function(o1,o2){
  return sort_o1_before_o2 ? -1 : sort_o1_after_o2 ? 1 : 0;
});

Generic, Powerful Answer

Define a custom non-enumerable sortBy function using a Schwartzian transform on all arrays :

(function(){
  if (typeof Object.defineProperty === 'function'){
    try{Object.defineProperty(Array.prototype,'sortBy',{value:sb}); }catch(e){}
  }
  if (!Array.prototype.sortBy) Array.prototype.sortBy = sb;

  function sb(f){
    for (var i=this.length;i;){
      var o = this[--i];
      this[i] = [].concat(f.call(o,o,i),o);
    }
    this.sort(function(a,b){
      for (var i=0,len=a.length;i<len;++i){
        if (a[i]!=b[i]) return a[i]<b[i]?-1:1;
      }
      return 0;
    });
    for (var i=this.length;i;){
      this[--i]=this[i][this[i].length-1];
    }
    return this;
  }
})();

Use it like so:

array.sortBy(function(o){ return o.date });

If your date is not directly comparable, make a comparable date out of it, e.g.

array.sortBy(function(o){ return new Date( o.date ) });

You can also use this to sort by multiple criteria if you return an array of values:

// Sort by date, then score (reversed), then name
array.sortBy(function(o){ return [ o.date, -o.score, o.name ] };

See http://phrogz.net/JS/Array.prototype.sortBy.js for more details.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 8
    Why just not `return b-a;` in the Simple Answer? – corbacho Feb 03 '14 at 09:33
  • 110
    Do not recommend creating new Date objects inside the sort method. Have hit production performance issues specifically for that reason. Do not allocate memory (and GC) inside a sort method. – MikeMurko Jul 13 '19 at 05:26
  • 17
    the first eg syntax gives error on angular7 : The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type – Surendranath Sonawane Jan 02 '20 at 13:05
  • 2
    @MikeMurko what did you do to fix it? – Sireini Apr 23 '20 at 10:25
  • 2
    @SURENDRANATHSONAWANE convert Date to Unix Timestamp: return new Date(b.date).getTime() - new Date(a.date).getTime(); – Robert Ostrowicki May 06 '20 at 07:05
  • @Sireini Use the Schwartzian transform version. – Phrogz May 06 '20 at 14:52
  • 11
    @Sireini Depends on the types/formatting of the date properties, but if it's a standard "Date" object, then @Gal's response is fastest & no allocations. The `a-b` comment is actually very slow in Chrome (https://jsperf.com/date-sort-mm/1). If the dates are just ISO strings, it's fastest to just compare them `a > b ? 1 : a < b ? -1 : 0`. – MikeMurko May 17 '20 at 14:11
  • 4
    On typescript you can do `array.sort((a: any, b: any) => (+new Date(b.date) - +new Date(a.date)))` – jstnno Jun 01 '20 at 16:16
  • 33
    If you are using TS and want to sort object by their date property, you can use the first option like this: `return +b.date - +a.date;` for descending order, and reversing the order of 'a' & 'b' for ascending order – Edwardcho Vaklinov Jun 24 '20 at 13:52
  • 1
    Creating two! date instances inside the sort function is terrible for performance. When you have a few objects is totally fine, but when you have hundreds or even thousands of them this is a serious performance bottleneck. – rafark Jul 04 '20 at 21:13
  • @MikeMurko Just wanted to say thanks for your answer here, helped me compare ISO strings where I was struggling with other methods. – James Brightman Nov 17 '20 at 13:32
  • 3
    Probably want to use `Date.parse()` instead of `new Date()`? – Zoe L Mar 23 '21 at 19:15
  • if you are using typescript, remember to user valueof(), new Date(a.date).valueOf() - new Date(b.date).valueOf() – nativelectronic Jan 29 '22 at 02:06
  • 1
    `(new Date(b.date)).getTime() - (new Date(a.date)).getTime()` is much faster then `new Date(b.date) - new Date(a.date)`. And if you avoid creating new Date objects inside the sort method as @MikeMurko commented the execution is considerably faster. – aRIEL Feb 15 '22 at 06:37
  • Mutating built-in prototypes is quite a bad idea IMO. Use a function instead. `const sortBy = (arr, compareFn) => ...` – CertainPerformance May 03 '22 at 23:52
  • Does items.sort((a,b)=>(Date.parse(b.date)-Date.parse(a.date)) get you out of the memory allocation problem? – Charney Kaye Nov 18 '22 at 02:26
  • @SurendranathSonawane do you have a more efficient solution if we need to sort by a date string key? – thdoan Apr 28 '23 at 09:10
347

@Phrogz answers are both great, but here is a great, more concise answer:

array.sort(function(a,b){return a.getTime() - b.getTime()});

Using the arrow function way

array.sort((a,b)=>a.getTime()-b.getTime());

found here: Sort date in Javascript

Teocci
  • 7,189
  • 1
  • 50
  • 48
Gal
  • 5,537
  • 1
  • 22
  • 20
  • 51
    Doing the math directly `a - b` would also work. So, `array.sort((a, b) => a - b)` (es6) – yckart Feb 26 '17 at 09:36
  • 2
    `a.getTime() - b.getTime()` is considerably faster then `a - b` – aRIEL Feb 15 '22 at 06:20
  • concise, concise, if you only have defined dates... – serge May 23 '22 at 08:16
  • 2
    To clarify, subtracting two `Date` objects is sufficient. The `-` operator calls `valueOf` method of the object for subtraction; and `Date.valueOf` returns the same value as `Date.getTime`. – Salman A Jun 30 '22 at 07:28
  • 9
    TypeScript throws an error on the simple "`a - b`" solution, but it works well with the `getTime` approach. – Kepi Aug 09 '22 at 12:58
127

After correcting the JSON this should work for you now:

var array = [{id: 1, date:'Mar 12 2012 10:00:00 AM'}, {id: 2, date:'Mar 8 2012 08:00:00 AM'}];


array.sort(function(a, b) {
    var c = new Date(a.date);
    var d = new Date(b.date);
    return c-d;
});
Ganesh Sanap
  • 1,386
  • 1
  • 8
  • 18
qw3n
  • 6,236
  • 6
  • 33
  • 62
76

Above answers are all good , here is my implementation of sorting date in ES6 way, I'm using Date.parse (is global Date object) this will convert string representation of Date to number of milliseconds. Instead of instantiating new Date object every time.

var array = ["2021-08-10T07:24:30.087+0000" , "2021-09-30T07:24:30.087+0000", "2021-10-13T07:24:30.087+0000"];

// sorting with latest date
array.sort((a,b) => Date.parse(b) - Date.parse(a))
Saran
  • 1,435
  • 11
  • 11
  • 1
    The answer snippet doesn't fit for the question. you can update your answer to match the question or delete it. – SAMUEL Nov 11 '21 at 13:28
  • 4
    This sorts a regular array of dates, not an array of objects with date properties, which was what the question was about. – Coreus Nov 03 '22 at 14:54
  • this is the only answer that works with TypeScript for me (also see the answer here: https://stackoverflow.com/a/54634547/827129) – fredrivett Nov 30 '22 at 09:41
66

Your data needs some corrections:

var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];

After correcting the data, you can use this piece of code:

function sortFunction(a,b){  
    var dateA = new Date(a.date).getTime();
    var dateB = new Date(b.date).getTime();
    return dateA > dateB ? 1 : -1;  
}; 

var array = [{id: 1, date: "Mar 12 2012 10:00:00 AM"},{id: 2, date: "Mar 28 2012 08:00:00 AM"}];
array.sort(sortFunction);​
gabitzish
  • 9,535
  • 7
  • 44
  • 65
  • 6
    [Don't forget to return `0` where necessary!](http://stackoverflow.com/q/20883421/1048572) – Bergi Apr 05 '17 at 05:13
  • 9
    For anyone using Typescript, I was able to sort by date using this function, while the other ones using the date subtraction failed. – Danchat Jan 14 '20 at 17:23
  • What is the differance? I see different types of quotes and a space, but that shouldn't matter, or am I missing something? – quick007 Dec 20 '21 at 04:33
30

I recommend GitHub: Array sortBy - a best implementation of sortBy method which uses the Schwartzian transform

But for now we are going to try this approach Gist: sortBy-old.js.
Let's create a method to sort arrays being able to arrange objects by some property.

Creating the sorting function

var sortBy = (function () {
  var toString = Object.prototype.toString,
      // default parser function
      parse = function (x) { return x; },
      // gets the item to be sorted
      getItem = function (x) {
        var isObject = x != null && typeof x === "object";
        var isProp = isObject && this.prop in x;
        return this.parser(isProp ? x[this.prop] : x);
      };
      
  /**
   * Sorts an array of elements.
   *
   * @param {Array} array: the collection to sort
   * @param {Object} cfg: the configuration options
   * @property {String}   cfg.prop: property name (if it is an Array of objects)
   * @property {Boolean}  cfg.desc: determines whether the sort is descending
   * @property {Function} cfg.parser: function to parse the items to expected type
   * @return {Array}
   */
  return function sortby (array, cfg) {
    if (!(array instanceof Array && array.length)) return [];
    if (toString.call(cfg) !== "[object Object]") cfg = {};
    if (typeof cfg.parser !== "function") cfg.parser = parse;
    cfg.desc = !!cfg.desc ? -1 : 1;
    return array.sort(function (a, b) {
      a = getItem.call(cfg, a);
      b = getItem.call(cfg, b);
      return cfg.desc * (a < b ? -1 : +(a > b));
    });
  };
  
}());

Setting unsorted data

var data = [
  {date: "2011-11-14T17:25:45Z", quantity: 2, total: 200, tip: 0,   type: "cash"},
  {date: "2011-11-14T16:28:54Z", quantity: 1, total: 300, tip: 200, type: "visa"},
  {date: "2011-11-14T16:30:43Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T17:22:59Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:53:41Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:48:46Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-31T17:29:52Z", quantity: 1, total: 200, tip: 100, type: "visa"},
  {date: "2011-11-01T16:17:54Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T16:58:03Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:20:19Z", quantity: 2, total: 190, tip: 100, type: "tab"},
  {date: "2011-11-14T17:07:21Z", quantity: 2, total: 90,  tip: 0,   type: "tab"},
  {date: "2011-11-14T16:54:06Z", quantity: 1, total: 100, tip: 0,   type: "cash"}
];

Using it

Finally, we arrange the array, by "date" property as string

//sort the object by a property (ascending)
//sorting takes into account uppercase and lowercase
sortBy(data, { prop: "date" });

If you want to ignore letter case, set the "parser" callback:

//sort the object by a property (descending)
//sorting ignores uppercase and lowercase
sortBy(data, {
    prop: "date",
    desc: true,
    parser: function (item) {
        //ignore case sensitive
        return item.toUpperCase();
    }
});

If you want to treat the "date" field as Date type:

//sort the object by a property (ascending)
//sorting parses each item to Date type
sortBy(data, {
    prop: "date",
    parser: function (item) {
        return new Date(item);
    }
});

Here you can play with the above example:
jsbin.com/lesebi

Community
  • 1
  • 1
jherax
  • 5,238
  • 5
  • 38
  • 50
  • 1
    IE11 had an issue with the line: if (toString.call(cfg) !== "[object Object]") cfg = {}; If you replace it with if (Object.prototype.toString.call(cfg) !== "[object Object]") cfg = {}; you will be all good with IE11 as well. – skribbz14 Jun 20 '18 at 21:53
21

This should do when your date is in this format (dd/mm/yyyy).

  sortByDate(arr) {
    arr.sort(function(a,b){
      return Number(new Date(a.readableDate)) - Number(new Date(b.readableDate));
    });

    return arr;
  }

Then call sortByDate(myArr);

TylerH
  • 20,799
  • 66
  • 75
  • 101
Edison D'souza
  • 4,551
  • 5
  • 28
  • 39
20

arr is an array of object and each object has date_prop which is a date. You can sort it in descending/decreasing order like this

 arr = arr.sort(function (a, b) {
      var dateA = new Date(a.date_prop).getTime();
      var dateB = new Date(b.date_prop).getTime();
      return dateA < dateB ? 1 : -1; // ? -1 : 1 for ascending/increasing order
    });
Viraj Singh
  • 1,951
  • 1
  • 17
  • 27
15

You could use sortBy in underscore js.

http://underscorejs.org/#sortBy

Sample:

var log = [{date: '2016-01-16T05:23:38+00:00', other: 'sample'}, 
           {date: '2016-01-13T05:23:38+00:00',other: 'sample'}, 
           {date: '2016-01-15T11:23:38+00:00', other: 'sample'}];

console.log(_.sortBy(log, 'date'));
Woppi
  • 5,303
  • 11
  • 57
  • 81
Robert
  • 2,357
  • 4
  • 25
  • 46
14

With ES6 arrow functions, you can further write just one line of concise code (excluding variable declaration).

Eg.:

var isDescending = true; //set to false for ascending
console.log(["8/2/2020","8/1/2020","8/13/2020", "8/2/2020"].sort((a,b) => isDescending ? new Date(b).getTime() - new Date(a).getTime() : new Date(a).getTime() - new Date(b).getTime()));

Since time does not exists with the above dates, the Date object will consider following default time for sorting:

00:00:00

The code will work for both ascending and descending sort. Just change the value of isDescending variable as required.

varad_s
  • 764
  • 1
  • 12
  • 24
13

Strings with dates are comparable in JavaScript (if they are syntactically the same), e.g.:

'2020-12-01' < '2020-12-02' == true

This means you can use this expression in a custom sort function:

var arr = [{id:1, date:'2020-12-01'}, {id:1, date:'2020-12-15'}, {id:1, date:'2020-12-12'}]

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

const sorted = arr.sort(sortByDate);
console.log(sorted);
sunwarr10r
  • 4,420
  • 8
  • 54
  • 109
9

i was able to achieve sorting using below lines:

array.sort(function(a, b)
{
   if (a.DueDate > b.DueDate) return 1;
   if (a.DueDate < b.DueDate) return -1;
})
Amay Kulkarni
  • 828
  • 13
  • 16
9

I'm going to add this here, as some uses may not be able to work out how to invert this sorting method.

To sort by 'coming up', we can simply swap a & b, like so:

your_array.sort ( (a, b) => {
      return new Date(a.DateTime) - new Date(b.DateTime);
});

Notice that a is now on the left hand side, and b is on the right, :D!

tchan
  • 751
  • 7
  • 19
James111
  • 15,378
  • 15
  • 78
  • 121
9

Simple one line solution for me to sort dates :

sort((a, b) => (a < b ? 1 : -1))
Benjamin Merchin
  • 1,029
  • 6
  • 11
8

I personally use following approach to sort dates.

let array = ["July 11, 1960", "February 1, 1974", "July 11, 1615", "October 18, 1851", "November 12, 1995"];

array.sort(function(date1, date2) {
   date1 = new Date(date1);
   date2 = new Date(date2);
   if (date1 > date2) return 1;
   if (date1 < date2) return -1;
})
Aravinda Meewalaarachchi
  • 2,551
  • 1
  • 27
  • 24
6
Adding absolute will give better results

var datesArray =[
      {"some":"data1","date": "2018-06-30T13:40:31.493Z"},
      {"some":"data2","date": "2018-07-04T13:40:31.493Z"},
      {"some":"data3","date": "2018-06-27T13:40:54.394Z"}
   ]

var sortedJsObjects = datesArray.sort(function(a,b){ 
    return Math.abs(new Date(a.date) - new Date(b.date)) 
});
5

Here is the shortest way to solve your problem.

  var array = [{id: 1, date: 'Mar 12 2012 10:00:00 AM'}, {id: 2, date: 'Mar 8 2012 08:00:00 AM'}];

  var sortedArray = array.sort((a,b) => Date.parse(new Date(a.date)) - Date.parse(new Date(b.date)));
4

Thank you Ganesh Sanap. sorting items by date field from old to new. Use it

 myArray = [{transport: "Air",
             load: "Vatican Vaticano",
             created: "01/31/2020"},
            {transport: "Air",
             load: "Paris",
             created: "01/30/2020"}] 

        myAarray.sort(function(a, b) {
            var c = new Date(a.created);
            var d = new Date(b.created);
            return c-d;
        });
Yanov
  • 655
  • 7
  • 13
  • 1
    What is the reason minus? – Yanov Jan 31 '20 at 19:08
  • c and d dates get converted to Timestamps and minus is used to compare these values. Here it is the documentation of sort and explanation of compare method used in sort: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#description I hope it helps :) – Donald Shahini Mar 19 '21 at 11:33
3
["12 Jan 2018" , "1 Dec 2018", "04 May 2018"].sort(function(a,b) {
    return new Date(a).getTime() - new Date(b).getTime()
})
Dan
  • 59,490
  • 13
  • 101
  • 110
2

For anyone who is wanting to sort by date (UK format), I used the following:

//Sort by day, then month, then year
for(i=0;i<=2; i++){
    dataCourses.sort(function(a, b){

        a = a.lastAccessed.split("/");
        b = b.lastAccessed.split("/");

        return a[i]>b[i] ? -1 : a[i]<b[i] ? 1 : 0;
    }); 
}
Andi
  • 115
  • 4
2

I have just taken the Schwartzian transform depicted above and made as function. It takes an array, the sorting function and a boolean as input:

function schwartzianSort(array,f,asc){
    for (var i=array.length;i;){
      var o = array[--i];
      array[i] = [].concat(f.call(o,o,i),o);
    }
    array.sort(function(a,b){
      for (var i=0,len=a.length;i<len;++i){
        if (a[i]!=b[i]) return a[i]<b[i]?asc?-1:1:1;
      }
      return 0;
    });
    for (var i=array.length;i;){
      array[--i]=array[i][array[i].length-1];
    }
    return array;
  }

function schwartzianSort(array, f, asc) {
  for (var i = array.length; i;) {
    var o = array[--i];
    array[i] = [].concat(f.call(o, o, i), o);
  }
  array.sort(function(a, b) {
    for (var i = 0, len = a.length; i < len; ++i) {
      if (a[i] != b[i]) return a[i] < b[i] ? asc ? -1 : 1 : 1;
    }
    return 0;
  });
  for (var i = array.length; i;) {
    array[--i] = array[i][array[i].length - 1];
  }
  return array;
}

arr = []
arr.push({
  date: new Date(1494434112806)
})
arr.push({
  date: new Date(1494434118181)
})
arr.push({
  date: new Date(1494434127341)
})

console.log(JSON.stringify(arr));

arr = schwartzianSort(arr, function(o) {
  return o.date
}, false)
console.log("DESC", JSON.stringify(arr));

arr = schwartzianSort(arr, function(o) {
  return o.date
}, true)
console.log("ASC", JSON.stringify(arr));
loretoparisi
  • 15,724
  • 11
  • 102
  • 146
2

If like me you have an array with dates formatted like YYYY[-MM[-DD]] where you'd like to order more specific dates before less specific ones, I came up with this handy function:

function sortByDateSpecificity(a, b) {
  const aLength = a.date.length
  const bLength = b.date.length
  const aDate = a.date + (aLength < 10 ? '-12-31'.slice(-10 + aLength) : '')
  const bDate = b.date + (bLength < 10 ? '-12-31'.slice(-10 + bLength) : '')
  return new Date(aDate) - new Date(bDate)
}
daviestar
  • 4,531
  • 3
  • 29
  • 47
0

Date form YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DD HH:mm:ss

  
let timeList = [

  {"date": "2023/08/07 09:15:42"},
  {"date": "2021/11/25 18:34:19"},
  {"date": "2007/05/14 07:56:30"},
  {"date": "2015/09/03 15:22:08"},
  {"date": "2010/03/22 12:47:53"}
 ]


  timeList.sort((a,b)=>new Date(a.date) - new Date(b.date))

  console.log(timeList)
Kamal Zaitar
  • 101
  • 1
  • 3
-1

Thanks for those brilliant answers on top. I have thought a slightly complicated answer. Just for those who want to compare different answers.

const data = [
    '2-2018', '1-2018',
    '3-2018', '4-2018',
    '1-2019', '2-2019',
    '3-2019', '4-2019',
    '1-2020', '3-2020',
    '4-2020', '1-2021'
]

let eachYearUniqueMonth = data.reduce((acc, elem) => {
    const uniqueDate = Number(elem.match(/(\d+)\-(\d+)/)[1])
    const uniqueYear = Number(elem.match(/(\d+)\-(\d+)/)[2])


    if (acc[uniqueYear] === undefined) {
        acc[uniqueYear] = []        
    } else{    
       if (acc[uniqueYear]  && !acc[uniqueYear].includes(uniqueDate)) {
          acc[uniqueYear].push(uniqueDate)
      }
    }

    return acc;
}, {})


let group = Object.keys(eachYearUniqueMonth).reduce((acc,uniqueYear)=>{
    eachYearUniqueMonth[uniqueYear].forEach(uniqueMonth=>{
    acc.push(`${uniqueYear}-${uniqueMonth}`)
  })
  
  return acc;
},[])

console.log(group);   //["2018-1", "2018-3", "2018-4", "2019-2", "2019-3", "2019-4", "2020-3", "2020-4"]


tcf01
  • 1,699
  • 1
  • 9
  • 24