Compare and filter out date properties in a object

Viewed 728

I have an object that looks like this:

    myObject = {
      publishedDate: string;
      Url: string;
      Title: string;
  }

The property "publishedDate" is a string in the format "19/01/2021". As the example, it can have a date in the future, i.e. a value greater than today. In other words I want to keep all objects where publishedDate is equal or less than today (and delete all that is over). The objects is saved in my state (array):

this.state.data

I first make a date variable for todays value to compare it with publishedDate. I also use moment() to format it in the same date format as the object:

let today = moment().format("DD/MM/YYYY");

I then use a filter method to compare and filter out the data:

  this.state.data.filter(item => new Date(item.publishedDate) >= new Date(today))

And I have also tried:

  this.state.data.filter(function(item) {
    
      if (new Date(item.publishedDate) >= new Date(today)) {
        return false;
      }
    return true;
  });

Not only it does not work, I still have all the objects in the array and nothing is filtered out. What is wrong with the code?

7 Answers

You can simply use the moment's inbuilt comparators like this

this.state.data.filter(item => moment(item.publishedDate,'DD/MM/YYYY').isSameOrAfter(today))

The Date constructor won't accept the format you are currently using, but it will recognize MM/DD/YYYY format. Moreover, filter retains the elements for which the function returns true, so you should be checking if the Date is less than or equal to the current Date.

const today = new Date;
this.state.data = this.state.data.filter(({publishedDate})=>{
    const [d, m, y] = publishedDate.split("/");
    return new Date(m + "/" + d + "/" + y) <= today;
});

One possibility, using a helper function notAfterToday, which takes a property name (in our case 'publishedDate') and returns a function which takes an object with that property name and reports whether that date is before or on the current date.

It does this by converting, say, the 18th day of December in 2020 into "20201218", and uses that string for the comparisons. Note that one advantage of this is that it only calls the Date constructor once, for the initial calculation of today's date.

const data = [{publishedDate: '18/12/2020', Url: 'http://example.com/1', Title: 'abc'}, {publishedDate: '19/01/2021', Url: 'http://example.com/2', Title: 'def'}, {publishedDate: '07/04/2014', Url: 'http://example.com/3', Title: 'ghi'}, {publishedDate: '19/07/2023', Url: 'http://example.com/4', Title: 'jkl'}, {publishedDate: '05/01/1966', Url: 'http://example.com/5', Title: 'mno'}, {publishedDate: '01/07/2041', Url: 'http://example.com/6', Title: 'pqr'}, {publishedDate: '08/05/2061', Url: 'http://example.com/7', Title: 'stu'}, {publishedDate: '10/08/1999', Url: 'http://example.com/8', Title: 'vwx'}]

const notAfterToday = (prop) => {
  const reorg = (date, [d, m, y] = date.split('/')) => y + m + d 
  const today = new Date()
  const compare = today .getFullYear() + 
                  String ((today .getMonth () + 1)) .padStart (2, '0') +
                  String (today .getDate ()) .padStart (2, '0')
  return (d) => compare >= reorg (d [prop])
}

console .log (data .filter (notAfterToday ('publishedDate')))
.as-console-wrapper {max-height: 100% !important; top: 0}

At the moment, new Date("19/01/2021") returns: Invalid Date.

This is a possible solution:

let today = moment().format("YYYY-MM-DD");

this.state.data.filter(function(item) {
    const pubDate = item.publishedDate.split('/').reverse().join('-');
    if (new Date(pubDate) >= new Date(today)) {
        return false;
    }
    return true;
});

You have to do a little fine-tuning your date string before comparing with today. You can try this-

const data = [
  {
    publishedDate: "19/01/2021",
    url: '',
    title: 'date1'
  },
  {
    publishedDate: "19/05/2021",
    url: '',
    title: 'date2'
  },
  {
    publishedDate: "13/01/2020",
    url: '',
    title: 'date3'
  },
  {
    publishedDate: "16/09/2009",
    url: '',
    title: 'date4'
  },
];

const parseDate = (dateString) => new Date(...dateString.split('/').reverse());


const result = data.filter(item => parseDate(item.publishedDate) <= new Date());

console.log(result);

Storing dates as strings is a code smell. It's harder to compare, store, and convert them as opposed to storing them either as a JS native Date format, or alternatives like Moment.JS date object.

Here is a trivial example of how you could do it if you stored your objects as date.

Notice that the third object got filtered out.

const myObject1 = {
  publishedDate: new Date("2019-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const myObject2 = {
  publishedDate: new Date("2020-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const myObject3 = {
  publishedDate: new Date("2099-01-01"), // NEW
  Url: "whatever",
  Title: "sample",
}

const arr = [myObject1, myObject2, myObject3];

const today = new Date();

const filtered = arr.filter((obj) => obj.publishedDate < today);

console.log(filtered);

Related