Determing if a value in an array is in the past, present or future

Viewed 56

I have two arrays like so:

 const exhibitiontypes = [
  {
   title: 'Past Exhibitions',
   type: 'past',
  },
  {
  title: 'Current Exhibitions',
  type: 'current',
  },
  {
  title: 'Upcoming Exhibitions',
  type: 'upcoming',
},
]

And

const exhibitions = [
  {
  name: 'Exhibition 1',
  startdate: new Date(2021, 08, 10),
  enddate: new (2021, 08, 15)
  },
  {
  name: 'Exhibition 2',
  startdate: new Date(2020, 08, 13),
  enddate: new Date(2020, 09, 25)
  },
  {
   name: 'Exhibition 3',
   startdate: new Date(),
   enddate: new Date(2021, 08, 5)
  }
 ]

And in my app, I map through the exhibition types and return an exhibitiontypepage, whcih would contain the past, current or upcoming exhibitions based on the start and end date of each exhibition.

const exhibitiontypes.map(type=> {
    return  <Exhibitiontypepage exhibitions={?} type={type}/>
 })

How can I filter the array of exhibitions to match only if the exhibition is in the past, present or future?

3 Answers

The easiest way is to compare to Date.now(), which is the current time in milliseconds. The easiest way to convert Date objects into milliseconds is to use the unary operator (+) to convert to a Number. After that, it's just a comparison of numeric values.

const now = Date.now();
exhibitions.map(entry => {
  if (+entry.enddate < now) {
    return exhibitiontypes[0];
  } else if (+entry.startdate <= now && +entry.enddate >= now) {
    return exhibitiontypes[1];
  } else {
    return exhibitiontypes[2];
  }
});

You'll have to filter the exhibitions before trying to render them. You could achieve this using a reducer function via array.reduce.

const exhibitions = [
  {
  name: 'Exhibition 1',
  startdate: new Date(2021, 08, 10),
  enddate: new Date(2021, 08, 15)
  },
  {
  name: 'Exhibition 2',
  startdate: new Date(2020, 08, 13),
  enddate: new Date(2020, 09, 25)
  },
  {
   name: 'Exhibition 3',
   startdate: new Date(),
   enddate: new Date(2021, 08, 5)
  }
]

const dateFilteredExhibitions = exhibitions.reduce((result, exb) => {
  const now = Date.now();
  if (now < +exb.startdate) {
    result.upcoming.push(exb);
  } else if (now > +exb.enddate) {
    result.past.push(exb)
  } else {
    result.current.push(exb)
  }
  return result;
}, {past: [], current: [], upcoming: []});

console.log(dateFilteredExhibitions);

Where you make this call to reduce is up to you. Probably you will do it after fetching the raw data from an API inside a useEffect and then something like setFilteredExhibitions(dateFilteredExhibitions).

const [filteredExhibitions, setFilteredExhibitions] = React.useState({
  past: [],
  current: [],
  upcoming: []
})

If its static data on your local system then you can do this outside the scope of the consuming React component or in a separate file and import it.

Once you have a variable you can reference which holds the filtered objects, the render call can access it by property name:

const exhibitiontypes.map(type=> {
    return  <Exhibitiontypepage exhibitions={filteredExhibitions[type.type]} type={type}/>
})

The below answer shows two concepts:

  1. Caching: this seems like a perfect opportunity to filter your data once and never do it again (unless you need to via an API call). This ensures a new data structure exhibitionByType is pre-filled with the filtered exhibitions and accessed easily anytime you want to see the filtered exhibition data. This is much more efficient than filtering every time you click on a button which consumes resources.

  2. I added some HTML so it is obvious to you what you will get and how to use it on your implementation. Have fun with it!

const currentDate = new Date(),
      exhibitiontypes = [
        {
         title: 'Past Exhibitions',
         type: 'past',
        },
        {
          title: 'Current Exhibitions',
          type: 'current',
        },
        {
          title: 'Upcoming Exhibitions',
          type: 'upcoming',
        },
      ],
      exhibitions = [
        {
          name: 'Past exhibition',
          startdate: new Date(2000, 08, 10),
          enddate: new Date(2000, 08, 15)
        },
        {
            name: 'Present exhibition',
            startdate: new Date(2020, 08, 13),
            enddate: currentDate
        },
        {
           name: 'Upcoming exhibition',
           startdate: new Date(),
           enddate: new Date(2023, 08, 5)
        }
      ];

// This array will serve as a cache, filtered only once and used continuously throughout the app. Index 0, 1, and 2 will correspond to 'past', 'present' and 'future' respectively
let exhibitionByType = [],
    resultElem = document.getElementById('result');

// Adding an inner array to serve as the list of filtered exhibitions by type
exhibitiontypes.forEach(elem => {
  elem.exhibitionList = [];

  exhibitionByType.push(elem);
});

// Filtering each exhibition by type
exhibitions.forEach(elem => {
  // Present by default
  let index = 1;

  if (currentDate < elem.enddate) {
    // Past
    index = 0;
  } else if (currentDate > elem.enddate) {
    // Future
    index = 2;
  }

  exhibitionByType[index].exhibitionList.push(elem);
});

// Filtering via newly formed exhibitionByType
function getExhibitionListByType (type) {
  resultElem.innerHTML = JSON.stringify(exhibitionByType[type]);
};
<button onclick="getExhibitionListByType(0)">Past</button>
<button onclick="getExhibitionListByType(1)">Present</button>
<button onclick="getExhibitionListByType(2)">Future</button>

<div id="result"></div>

Related