handsome
handsome

Reputation: 2402

Sort array by date in Javascript

I´m using sort() to order an Array by date

elements = data.sort(function(a, b) {
    return a.date.getTime() - b.date.getTime()
});

the problem is that some elements are missing the date (or the date is invalid) and that´s causing this error:

Cannot read property 'getTime' of undefined

update: I have moment ready to use

Where should I check if date is valid date and then use it to order the array?

update: this is the data I have

[{
        "date": "2019-06-15 14:57:13",
        "user": "john"
    },
    {
        "date": "2019-06-15 05:48:01",
        "user": "mike"
    },
    {
        "date": "bad-date-format",
        "user": "donna"
    },
    {
        "date": "2019-06-08 10:45:09",
        "user": "Ismil"
    },
    {
        "date": "",
        "user": "Daniel17"
    }
]

and this is the output I expect

[
    {
        "date": "2019-06-15 14:57:13",
        "user": "john"
    },
    {
        "date": "2019-06-15 05:48:01",
        "user": "mike"
    },
    {
        "date": "2019-06-08 10:45:09",
        "user": "Ismil"
    },
    {
        "date": "bad-date-format",
        "user": "donna"
    },
    {
        "date": "",
        "user": "Daniel17"
    }
]

Upvotes: 2

Views: 2162

Answers (7)

Ammar
Ammar

Reputation: 820

You don't have to check if the string is a valid date.

Here's a working code:

const data = [{
        "date": "2019-06-15 14:57:13",
        "user": "john"
    },
    {
        "date": "2019-06-15 05:48:01",
        "user": "mike"
    },
    {
        "date": "bad-date-format",
        "user": "donna"
    },
    {
        "date": "2019-06-08 10:45:09",
        "user": "Ismil"
    },
    {
        "date": "",
        "user": "Daniel17"
    }
];

const elements = data.sort((a, b) => (new Date(b.date).getTime() || -Infinity) - (new Date(a.date).getTime() || -Infinity));
console.log(elements);

The trick behind the above code is that new Date() will give an Invalid Date object if you pass an invalid date string to it, which will return NaN if you executed its getTime() method.

Now because you want all Invalid Dates to be at the bottom, then your sorting function should treat these Invalid Dates as the lowest rated in your array, and that's what -Infinite means (the lowest number. If you add any number to it will lead to -Infinite).

I assume that it doesn't matter how Invalid Dates are sorted at the bottom of your array.

Upvotes: 5

Nina Scholz
Nina Scholz

Reputation: 386550

You could check if the property exists has the wanted format and then sort the date by string descending and if one has no valid format, take the delta of the boolean values.

function checkDate(string) {
    return typeof string === 'string'
        && /\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(string);
}

var array = [{ date: "2019-06-15 14:57:13", user: "john" }, { date: "2019-06-15 05:48:01", user: "mike" }, { date: "bad-date-format", user: "donna" }, { date: "2019-06-08 10:45:09", user: "Ismil" }, { date: "", user: "Daniel17" }];

array.sort((a, b) => {
    var aC = checkDate(a.date),
        bC = checkDate(b.date);

    return aC && bC
        ? b.date.localeCompare(a.date)
        : bC - aC;
});

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 2

Akrion
Akrion

Reputation: 18515

You can use Date.parse to make sure you have a valid date and when you do for both of your parameters sort them. Otherwise sort the one with the valid date "higher":

let data = [{ "date": "2019-06-15 14:57:13", "user": "john" }, { "date": "2019-06-15 05:48:01", "user": "mike" }, { "date": "bad-date-format", "user": "donna" }, { "date": "2019-06-08 10:45:09", "user": "Ismil" }, { "date": "", "user": "Daniel17" } ]

let result = data.sort((a,b) => Date.parse(a.date) && Date.parse(b.date)
  ? new Date(b.date).getTime() - new Date(a.date).getTime()
  : Date.parse(a.date) ? -1 : 0
)

console.log(result)

Upvotes: 1

Wimanicesir
Wimanicesir

Reputation: 5121

data.sort(function(a, b) {
    if (typeof a.date !== 'undefined' && typeof b.date !== 'undefined') {
      return a.date.getTime() - b.date.getTime()
    }
    return 0
});

Working simple example

data = [{date:"100"},{date:null},{date:"1"}, {nodate:"10"}];

data.sort(function(a, b) {
    if (typeof a.date !== 'undefined' && typeof b.date !== 'undefined') {
      return a.date - b.date
    }
    return 0
});

console.log(data)

Upvotes: -1

Code Maniac
Code Maniac

Reputation: 37755

You can check before using getTime

let data = [{
  date: new Date('2019-01-03T00:00:00.000Z')
},{
  date: new Date('2020-01-03T00:00:00.000Z')
},{
  date: new Date('2018-01-03T00:00:00.000Z')
}, {}]

data.sort((a, b)=>{
  if(!isNaN(new Date(a.date).getTime()) && !isNaN(new Date(b.date).getTime())){
  return a.date.getTime() - b.date.getTime()
  } 
  return Infinity
});

console.log(data);

Upvotes: -2

Ayush Gupta
Ayush Gupta

Reputation: 9285

As per OPs comment

order by date descending and the ones with no corrupt data should go at the beginning of the array

let data = [{
  date: new Date('2019-01-03T00:00:00.000Z')
},{
  date: new Date('2020-01-03T00:00:00.000Z')
},{
  date: new Date('2018-01-03T00:00:00.000Z')
}, {}]


function safeGetTime(obj) {
  if (obj && obj.date && obj.date.getTime) {
    return obj.date.getTime();
  }
  return Number.MAX_SAFE_INTEGER; // replace with `return 0` to put invalid data at end of array
}

data.sort(function(a, b) {
  return safeGetTime(b) - safeGetTime(a)
});

console.log(data);

Upvotes: 0

Maheer Ali
Maheer Ali

Reputation: 36564

You can use && operator.

data.sort(function(a, b) {
    return (a.date && b.date && a.date.getTime && b.date.getTime && a.date.getTime() - b.date.getTime()) || 0
});

I would prefer an helper function.

const validDate = (...arr) => arr.every(x => x.date && x.date.getTime);
data.sort(function(a, b) {
    return (validDate(a,b) && a.date.getTime() - b.date.getTime()) || 0
});

Upvotes: -2

Related Questions