Assuming your date format is consistently DD/MM/YYYY:
dates.sort(function(a, b){
var aa = a.split('/').reverse().join(),
bb = b.split('/').reverse().join();
return aa < bb ? -1 : (aa > bb ? 1 : 0);
});
... otherwise you will have to compare Date objects if you require more flexibility.
Assuming your date format is consistently DD/MM/YYYY:
dates.sort(function(a, b){
var aa = a.split('/').reverse().join(),
bb = b.split('/').reverse().join();
return aa < bb ? -1 : (aa > bb ? 1 : 0);
});
... otherwise you will have to compare Date objects if you require more flexibility.
Try this (feel free to ask for details) :
dates.sort(function (a, b) {
// '01/03/2014'.split('/')
// gives ["01", "03", "2014"]
a = a.split('/');
b = b.split('/');
return a[2] - b[2] || a[1] - b[1] || a[0] - b[0];
});
Translation of the last line :
return return
a[2] - b[2] years comparison if year A - year B is not 0
|| or
a[1] - b[1] months comparison if month A - month B is not 0
|| or
a[0] - b[0]; days comparison
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort.
UPDATE: You can run performance tests I prepared based on various code samples from the answers to this question: https://jsperf.com/cr-se-date-array-sorting/1. When I ran them, I see that my code is second best performing. The best is the one by @Kevin Cline (up voted!).

Here's my take on it. The following code uses the same idea about the string representation of date that is directly comparable for sorting.
It is not possible to tell in advance how performant will this solution be compared to one you presented above. It all depends a lot on how many dates are being sorted. If you deal with tons of dates, there will be many more invocations to the arrow function we're passing to sort(...). Therefore, it's not good to keep translating the date via split() every time our arrow function is being used.
Instead, I recommend three steps:
- Translate dates into a sortable representation (one time). Use
.map(). - Do the sorting with
.sort(). The values will be put in a lexicographical order. - Translate the sorted dates back into original representation.
This will guarantee that each date is translated at most twice, which makes the entire solution more performant for large Ns.
Also, Notice that steps #1 and #3 can use same exact implementation, which I extracted.
const reverseDateRepresentation = date => {
let parts = date.split('-');
return `${parts[2]}-${parts[1]}-${parts[0]}`;
};
const sortedDates = ['01-02-2018', '02-01-2018', '01-01-2018', '31-12-2017']
.map(reverseDateRepresentation)
.sort()
.map(reverseDateRepresentation);
console.log(sortedDates);
Produces result:
["31-12-2017", "01-01-2018", "02-01-2018", "01-02-2018"]
Little note. I think, that from the "big O" point of view we haven't improve the algorithm. Since .map(reverseDateRepresentation) is \, the performance of the entire solution is limited by the
.sort() (which is probably \). The way we're potentially improving solution is by making sure that the constants in our "big O" cost are as small as we can achieve.
Nevertheless, if we'd put the performance as top criteria of the solution, I'd learn as much as I can about the real data being processed; as well as conducted a thorough performance test.
In real life scenario, however, I personally never put performance above readability, because I believe that lack of readability is eventually the same thing as lack of correctness ...and correctness is almost always more important than performance (few exceptions are known though).
Simply compare the characters in order from most significant to least significant:
let indices = [ 6, 7, 8, 9, 3, 4, 0, 1 ];
var dates = ["02-02-2018", "02-01-2018", "01-02-2018", "01-01-2018", "12-31-2017" ];
dates.sort((a, b) => {
var r = 0;
indices.find(i => r = a.charCodeAt(i) - b.charCodeAt(i));
return r;
});
For each comparison this examines the minimum number of characters. Hard to imagine any other solution being faster, except maybe using a for loop instead of find.
Never use the new Date(string) constructor nor Date.parse() to parse a date string as neither method lets you supply a specific format or locale information. (Annoyingly, JavaScript's built-in Intl does not support parsing, only formatting).
JavaScript's new Date(string) and Date.parse(string) functions use tend to use the user's computer's regional settings to parse a date - if a user is using Windows' en-US settings without realising it then Date.parse(string) and new Date(string) will interpret dates as MM/dd/yyyy instead of their correct regional settings. However browsers tend to try to parse anything you throw at them and if they see 12/31/2019 or 31/12/2019 then they'll both be parsed as 2019-12-31 regardless of their computer regional settings - things only fall-apart if they're given 5/7/2019, for example which will be interpreted as 2019-05-07 if they're in the US or 2019-07-05 if they're in the UK.
Unfortunately you'll need to parse them manually or use a peer-reviewed library like Moment.JS (because writing date libraries is hard).
let dates = [ "03/12/2019", "17/10/2020", "02/12/2019", ... ];
function parseDate( ddMMyyyy ) {
const components = ddMMyyyy.split( '/' );
if( components.length != 3 ) return null;
const dd = parseInt( components[0] );
const MM = parseInt( components[1] );
const yyyy = parseInt( components[2] );
// Component range checking:
if( dd >= 1 && dd <= 31 && MM >= 1 && MM <= 12 && yyyy >= 0 && yyyy <= 9999 ) {
return new Date( yyyy, MM - 1, dd ); // `MM - 1` because JavaScript months are 0-based.
}
else {
return null;
}
}
let sortedParsedDates = dates
.map( parseDate )
.filter( dt => dt instanceof Date )
.sort( ( x, y ) => x.getTime() - y.getTime() );
It's because the dates are in UK format, so it'll order them by ascending day, regardless of the month or year. If you convert them to YYYY-MM-DD format it'll sort them correctly for you:
let a = ["03/12/2019", "17/10/2020", "02/12/2019", "08/12/2019", "13/02/2020"]; // etc.
function ukToUsDate(ukDate) {
let dateArr = ukDate.split('/');
return `${dateArr[2]}-${dateArr[1]}-${dateArr[0]}`;
}
for (let i = 0; i < a.length; i++) {
a[i] = ukToUsDate(a[i]);
}
a.sort((b, a) => {
if (b > a) {
return 1;
}
if (b < a) {
return -1;
}
return 0;
});
The sort needs date.getTime()-date.getTime()
In this case you can leave off the getTime since it will be used anyway
var contributions = [
{paymentDate: "9/2/2014"},
{paymentDate: "9/7/2014"},
{paymentDate: "10/8/2015"},
{paymentDate: "1/9/2014"},
{paymentDate: "3/9/2015"}
]
contributions.sort(function(a, b) {
return new Date(a.paymentDate) - new Date(b.paymentDate)
})
console.log(contributions)
This is an easy-to-understand solution:
for (var i = 0; i < contributions.length; i++) {
var dateI = new Date(contributions[i].paymentDate);
for (var j = i + 1; j < contributions.length; j++) {
var dateJ = new Date(contributions[j].paymentDate);
if (dateI > dateJ) {
var aux = contributions[i];
contributions[i] = contributions[j];
contributions[j] = aux;
dateI = dateJ;
}
}
}
If you want an already existent solution, then:
contributions.sort(function(a, b) {
return new Date(a.paymentDate) - new Date(b.paymentDate);
});
To sort an array of object by dates of format (DD.MM.YYYY)
datesObject.sort(function(a, b){
let curr = a.date.split('.').reverse().join();
let prev = b.date.split('.').reverse().join();
return curr < prev ? -1 : (curr > prev ? 1 : 0);
});
- Create
Dateobjects from date strings - Sort ascending based on
valueOf
const parseDate = (dateStr) => {
const [d, m, y] = dateStr.split('.')
.map(Number)
return new Date(y, m - 1 /* month is 0-indexed */, d)
}
const sortDatesAsc = (dateStr1, dateStr2) => {
return parseDate(dateStr2).valueOf - parseDate(dateStr1).valueOf
}
console.log([
'10.01.2010',
'01.10.2010',
'10.10.2020',
].sort(sortDatesAsc))
It's not interpreting the date the way you think it is. For example,
console.log(new Date("05/01/2015 12:35"));
produces for me:
Date 2017-05-01T19:35:00.000Z
which shows that it's expecting the date to be in MM/dd/yyyy format.
You can either roll your own solution or use one of the libraries out there. There are a lot of solutions available. I personally like moment.js which allows date format strings.
Another example, quoted from this answer, adds date parsing format control to strings:
String.prototype.toDate = function(format) { var normalized = this.replace(/[^a-zA-Z0-9]/g, '-'); var normalizedFormat= format.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-'); var formatItems = normalizedFormat.split('-'); var dateItems = normalized.split('-'); var monthIndex = formatItems.indexOf("mm"); var dayIndex = formatItems.indexOf("dd"); var yearIndex = formatItems.indexOf("yyyy"); var hourIndex = formatItems.indexOf("hh"); var minutesIndex = formatItems.indexOf("ii"); var secondsIndex = formatItems.indexOf("ss"); var today = new Date(); var year = yearIndex>-1 ? dateItems[yearIndex] : today.getFullYear(); var month = monthIndex>-1 ? dateItems[monthIndex]-1 : today.getMonth()-1; var day = dayIndex>-1 ? dateItems[dayIndex] : today.getDate(); var hour = hourIndex>-1 ? dateItems[hourIndex] : today.getHours(); var minute = minutesIndex>-1 ? dateItems[minutesIndex] : today.getMinutes(); var second = secondsIndex>-1 ? dateItems[secondsIndex] : today.getSeconds(); return new Date(year,month,day,hour,minute,second); };Example:
"22/03/2016 14:03:01".toDate("dd/mm/yyyy hh:ii:ss"); "2016-03-29 18:30:00".toDate("yyyy-mm-dd hh:ii:ss");
The first rule with dates is do not use the Date constructor (or Date.parse) to parse strings. Do it manually. A library can help, but if you only have to deal with one format, then a simple function will suffice.
You can convert the strings to a format that sorts, say ISO 8601, or convert them to dates and sort those, e.g.
var data = [{id:1,date:"04/04/2017 17:47"},
{id:2,date:"05/01/2015 12:35"},
{id:3,date:"31/02/2017 10:00"},
{id:4,date:"31/02/2017 12:00"}];
function parseDMYhm(s) {
var b = s.split(/\D/);
return new Date(b[2], b[1]-1, b[2], b[3], b[4]);
}
data.sort(function(a, b) {
return parseDMYhm(a.date) - parseDMYhm(b.date);
});
console.log(data);
Note that the parse function does not validate the date values, so 31/02/2017 will be treated as 3 March, 2017. If you want to validate the date values, that is one more line of code.
An alternative to sort as strings might be:
var data = [{id:1,date:"04/04/2017 17:47"},
{id:2,date:"05/01/2015 12:35"},
{id:3,date:"31/02/2017 10:00"},
{id:4,date:"31/02/2017 12:00"}];
// Reformat DD/MM/YYYY HH:mm as YYYY-MM-DDTHH-mm
function formatStringAsISO(s) {
var b = s.split(/\D/);
return b[2] + '-' + b[1] + '-' + b[0] + 'T' + b[3] + ':' + b[4];
}
data.sort(function(a, b) {
return formatStringAsISO(a.date).localeCompare(formatStringAsISO(b.date));
});
console.log(data);