tonyf
tonyf

Reputation: 35557

Sort array on string date value not returning the correct result order (descending)

I am trying to sort an array, on a string date, and I am having some issues with it.

My array is called: myArray and has the following sample info:

0: {…}
​​
deployed_date: "29/01/2019 14:08:44"
​​last_restored_date: "11/01/2019 11:22:22"

1: {…}
​​
deployed_date: "29/01/2019 14:08:19"
​​
2: {…}
​​
​​deployed_date: "29/01/2019 11:34:23"
​​
3: {…}
​​
deployed_date: "11/02/2019 11:24:33"
​​
4: {…}
​​
deployed_date: "11/02/2019 11:24:24"
​​last_restored_date: "11/01/2019 11:25:42"

I have used both Lodash and native JavaScript sorting, but unfortunately I am not able to sort on this deployed_date alone in descending order.

FYI, I am also using momentjs:

myArray[key].deployed_date = moment(value.deployed_date,'YYYYMMDDHHmmss').format('DD/MM/YYYY HH:mm:ss');

I have used:

_.orderBy(myArray, ['deployed_date'],['desc']) //lodash

as well as

myArray.sort()

The order is appearing as in my array above.

I'm not sure if it's to do with the fact that array indexes 1,2 and 3 do not have a last_restored_date value but for some reason, the array is not sorted correctly by deployed_date desc.

The result I expect is:

11/02/2019 11:24:33
11/02/2019 11:24:24
29/01/2019 14:08:44
29/01/2019 14:08:19
29/01/2019 11:34:23

How can I achieve the expected result order shown here?

Upvotes: 0

Views: 969

Answers (5)

Marouane Fazouane
Marouane Fazouane

Reputation: 1329

The way I see it, your usage of lodash’s orderBy is good and it should have ordered your data as expected. What’s causing you issues is that you're sorting strings not dates and your strings are in the format DD/MM/YYYY which is not ideal if you want to sort them: 01/01/2019 is « before » 31/12/2018 (although nonsensical).

What you can do: 1/ you can either have Date or Moment data instead of strings 2/ or format your dates as YYYY-MM-DD ... etc 3/ or pass a function to the sorting function ˋ_.orderBy(myArray, [d => moment(d.deployed_data, ...)], ['desc'])`

Upvotes: 0

Yatin Darmwal
Yatin Darmwal

Reputation: 76

You can use map on the resulting array like this to obtain the expected result

let new_arr = foo.map( (obj) => {  
   return obj.deployed_date;
 ); 

Hope it makes sense

Upvotes: 0

molamk
molamk

Reputation: 4116

const toDate = str => {
  const [d, t] = str.split(' ')
  return new Date(`${d.split('/').reverse().join('-')}T${t}Z`).getTime();
};

const compareByDate = (x, y) => toDate(y.deployed_date) - toDate(x.deployed_date);

const arr = [
  {deployed_date: "29/01/2019 14:08:44"},
  {deployed_date: "29/01/2019 14:08:19"},
  {deployed_date: "29/01/2019 11:34:23"},
  {deployed_date: "11/02/2019 11:24:33"},
  {deployed_date: "11/02/2019 11:24:24"}
];

arr.sort(compareByDate);
console.log(arr);

Explanation

  1. Convert each date into an ISO string date (standard format)
  2. Extract a number from that string (using Date.getTime()) to facilitate comparisons. Use the Date constructor to change the string into a Date. Then convert that date into milliseconds
  3. Since you want a decreasing order (reversed), make sure that in your comparator function you reverse the operands. (x, y) => y - x;
  4. Once you have numbers as dates, you can use Array.sort based on the key deployed_date

Note

The ISO format we want to use is YYYY-MM-DDTHH:MM:SSZ. And since we have 29/01/2019 14:08:44 we need to do some processing.

  1. Split the string with ' ' to separate time and date
  2. Since the split return an array of 2 items, you can use the array destructuring operation.
  3. Split the date with '/' and reverse the array, since we want YYYY-MM_DD. Then join using the '-' character
  4. Create the date using new Date(...) then convert it into milliseconds using Date.getMilliseconds()

Upvotes: 0

Shidersz
Shidersz

Reputation: 17190

One solution is to map your dates to standard format when comparing the deployed_date of two objects using String::localeCompare():

const myArray = [
  {deployed_date: "29/01/2019 14:08:44", last_restored_date: "11/01/2019 11:22:22"},
  {deployed_date: "29/01/2019 14:08:19"},
  {deployed_date: "29/01/2019 11:34:23"},
  {deployed_date: "11/02/2019 11:24:33"},
  {deployed_date: "11/02/2019 11:24:24", last_restored_date: "11/01/2019 11:25:42"}
];

myArray.sort((a, b) =>
{
    let [aDate, aHour] = a.deployed_date.split(" ");
    let [bDate, bHour] = b.deployed_date.split(" ");
    let [aDay, aMonth, aYear] = aDate.split("/");
    let [bDay, bMonth, bYear] = bDate.split("/");
    let newADate = `${aYear}/${aMonth}/${aDay} ${aHour}`;
    let newBDate = `${bYear}/${bMonth}/${bDay} ${bHour}`;
    
    return newBDate.localeCompare(newADate);
});

console.log(myArray);

Upvotes: 0

Vikash_Singh
Vikash_Singh

Reputation: 1896

Please use moment library to firstly format the date in 'DD/MM/YYYY HH:mm:ss' and below code will sort and returns result as you are looking for x.sort((a,b)=>{ return moment(a,'DD/MM/YYY HH:mm:ss').isAfter(moment(b,'DD/MM/YYY HH:mm:ss')) ? -1 : 1 })

Upvotes: 1

Related Questions