javascriptarrayssortingdatetimeangular-moment

Filter an array of ISO date by days of the week in javascript


I have an array of ISO dates I'm trying to sort and get only the next seven days from it

Here is the sample

Here is the sample code

daysdata = [{time: '2022-01-23T11:00:00Z', data: {…}},   
     {time: '2022-01-23T12:00:00Z', data: {…}},   
     {time: '2022-01-24T11:00:00Z', data: {…}},   
     {time: '2022-01-24T12:00:00Z', data: {…}},   
     {time: '2022-01-24T17:00:00Z', data: {…}},   
     {time: '2022-01-24T23:00:00Z', data: {…}},   
     {time: '2022-01-25T00:00:00Z', data: {…}},   
     {time: '2022-01-25T04:00:00Z', data: {…}},   
     {time: '2022-01-25T05:00:00Z', data: {…}},   
     {time: '2022-01-25T06:00:00Z', data: {…}},    
     {time: '2022-01-25T07:00:00Z', data: {…}},   
     {time: '2022-01-25T14:00:00Z', data: {…}},        
     {time: '2022-01-25T15:00:00Z', data: {…}},    
     {time: '2022-01-26T13:00:00Z', data: {…}},
     {time: '2022-01-26T14:00:00Z', data: {…}},
     {time: '2022-01-26T15:00:00Z', data: {…}},
     {time: '2022-01-27T13:00:00Z', data: {…}},
     {time: '2022-01-27T14:00:00Z', data: {…}},
     {time: '2022-01-27T15:00:00Z', data: {…}},
     {time: '2022-01-28T14:00:00Z', data: {…}},     
     {time: '2022-01-28T15:00:00Z', data: {…}},    
     {time: '2022-01-28T16:00:00Z', data: {…}},    
     {time: '2022-01-29T18:00:00Z', data: {…}},    
     {time: '2022-01-29T19:00:00Z', data: {…}},    
     {time: '2022-01-30T08:00:00Z', data: {…}},    
     {time: '2022-01-30T09:00:00Z', data: {…}},    
     {time: '2022-01-30T10:00:00Z', data: {…}},    
     {time: '2022-01-30T11:00:00Z', data: {…}},    
    ]

That is the sample code.


Solution

  • An algorithm is:

    1. Sort the data by the value of the time property
    2. Find the index of the first day on the same date as the start date
    3. If an element is found, push that element into an array
    4. Increment the search date by 1 day

    A lexical sort is used to sort on time and to find the records to return as it's an ISO 8601 string. Conversion to Date objects will work too but that seems unnecessary.

    To select each date, dStart is set to the start of the UTC day and dEnd is set to the end of the UTC day. If no date is found in that range, none is added to the array. This prevents the case of a multi day gap in the data producing multiple entries of the same object (i.e. the first one after the gap) in the selected array.

    If this should be based on local dates, then use setHours instead of setUTCHours.

    /* Given data as an array of objects, return
     * first on date plus first on next n days
     * Dates are UTC, not local
     */
    function getFirstNDays(data, n = 1, date = new Date()) {
    
      // Make sure n is a positive integer
      if (n % 1 || n < 0) return;
    
      data.sort((a, b) => a.time.localeCompare(b.time)); 
    
      let dStart = new Date(date);
      dStart.setUTCHours(0,0,0,0);
    
      let dEnd = new Date(dStart);
      dEnd.setUTCHours(23,59,59,999);
      let selected = [];
      
      while (n--) {
        let index = data.findIndex(obj => obj.time >= dStart.toISOString() && obj.time <= dEnd.toISOString());
    
        // If record found, add to selected array
        if (index != -1) {
          selected.push(data[index]);
        }
    
        dStart.setUTCDate(dStart.getUTCDate() + 1);
        dEnd.setUTCDate(dEnd.getUTCDate() + 1);
      }
    
      // Return selected values
      return selected;
    }
    
    let daysdata = [
      {time: '2022-01-20T11:00:00Z', data: {}},   
      {time: '2022-01-23T11:00:00Z', data: {}},   
      {time: '2022-01-23T12:00:00Z', data: {}},   
      {time: '2022-01-24T11:00:00Z', data: {}},   
      {time: '2022-01-24T12:00:00Z', data: {}},   
      {time: '2022-01-24T17:00:00Z', data: {}},   
      {time: '2022-01-24T23:00:00Z', data: {}},   
      {time: '2022-01-25T00:00:00Z', data: {}},   
      {time: '2022-01-25T04:00:00Z', data: {}},   
      {time: '2022-01-25T05:00:00Z', data: {}},   
      {time: '2022-01-25T06:00:00Z', data: {}},    
      {time: '2022-01-25T07:00:00Z', data: {}},   
      {time: '2022-01-25T14:00:00Z', data: {}},        
      {time: '2022-01-25T15:00:00Z', data: {}},    
      {time: '2022-01-26T13:00:00Z', data: {}},
      {time: '2022-01-26T14:00:00Z', data: {}},
      {time: '2022-01-26T15:00:00Z', data: {}},
      {time: '2022-01-27T13:00:00Z', data: {}},
      {time: '2022-01-27T14:00:00Z', data: {}},
      {time: '2022-01-27T15:00:00Z', data: {}},
      {time: '2022-01-28T14:00:00Z', data: {}},     
      {time: '2022-01-28T15:00:00Z', data: {}},    
      {time: '2022-01-28T16:00:00Z', data: {}},    
      {time: '2022-01-29T18:00:00Z', data: {}},    
      {time: '2022-01-29T19:00:00Z', data: {}},    
      {time: '2022-01-30T08:00:00Z', data: {}},    
      {time: '2022-01-30T09:00:00Z', data: {}},    
      {time: '2022-01-30T10:00:00Z', data: {}},    
      {time: '2022-01-30T11:00:00Z', data: {}},    
    ];
    
    console.log(getFirstNDays(daysdata, 7, new Date(Date.UTC(2022,0,23))));

    Updated to suit updated requirements.