Как группировать массив дат в периоды startdate-enddate? Если между датами отсутствует один день недели, то новый период начинается в Javascript

20.01.2017
23.01.2017
24.01.2017
25.01.2017
26.01.2017
27.01.2017
31.01.2017
01.02.2017

Скажем, у меня есть эти даты. Все эти даты-рабочие дни.
Выход должен быть

20.01.2017-27.01.2017
and
31.01.2017-01.02.2017

С 30 января рабочий день и поэтому первый период не продолжается и начинается новый период.

Как лучше всего к этому подойти.

Я думал взять первую дату в массиве и поместить ее в новый массив. Затем сравнение следующей даты в массиве с предыдущей, если это следующий день (игнорируя выходные). Если это не nextday, то возьмите предыдущую дату и поместите ее в массив в качестве даты окончания, а затем начните новый массив следующего периода.

4 ответа

  1. Получите свое первое свидание (я предлагаю вам их заказать, как в вашем примере данных они являются) и сохранить его в переменной для даты начала.

    Сохраните то же значение в другой переменной для даты окончания.

    Теперь петля через ваши даты, проверяя, если текущая петля дата следующая после текущей даты окончания. Если это так, сохраните текущую дату цикла в переменную даты окончания и перейдите к следующему циклу. Если это не возвращает текущие даты начала и окончания и сохраняет текущую дату цикла как новую дату начала периода, продолжайте до конца цикла и возвращайте текущие переменные.

  2. Это был бы мой подход, хотя и не самый короткий или, возможно, лучший способ столкнуться с этим. Просто примите это как идею

    var array = [
        "20.01.2017",
        "23.01.2017",
        "24.01.2017",
        "25.01.2017",
        "26.01.2017",
        "27.01.2017",
        "31.01.2017",
        "01.02.2017"
    ];
    
    var isNextDay = function(day, nextDay) {
        var day1 = new Date(day.slice(3, 6) + day.slice(0, 3) + day.slice(6)); //had to format the date this way to make a valid date
        day1.setDate(day1.getDate() + 1); //sets the next day, nextday of 30 or 31(last day of month) is 1
        var day2 = new Date(nextDay.slice(3, 6) + nextDay.slice(0, 3) + nextDay.slice(6));
        if (day1.getTime() === day2.getTime()) {
            return true;
        } else {
            return false;
        }
    }
    
    var dateGroup = function(dateStrings) {
        var res = [];
        var aux = dateStrings[0] + "-";
        for (var i = 1; i < dateStrings.length; i++) {
            if (!isNextDay(dateStrings[i - 1], dateStrings[i])) {
                aux += dateStrings[i - 1];
                res.push(aux);
                aux = dateStrings[i] + "-";
            }
       }
        aux += dateStrings[dateStrings.length - 1];
        res.push(aux); //this is because the last one never gets pushed
        return res;
    }
    
    var output = dateGroup(array);
    
  3. Вы можете зациклиться на датах и вычислить, как должна выглядеть строка для следующей даты, а затем сравнить, чтобы увидеть, если это то же самое. Если нет, закончите предыдущий период и начните новый.

    Вы можете использовать библиотеку для анализа и форматирования дат, но простые функции для выполнения работы — это всего лишь пара строк, например

    var dates = ['20.01.2017','23.01.2017','24.01.2017',
                 '25.01.2017','26.01.2017','27.01.2017',
                 '31.01.2017','01.02.2017'];
    
    /* Parse date in format D/M/YYYY
    ** @param {string} s - date to parse lke 23.1.2017
    ** @returns {Date}
    */
    function parseDMY(s) {
      var b = s.split(/\D/);
      return new Date(b[2], b[1]-1, b[0]);
    }
    
    /* Format a date in DD/MM/YYYY with supplied separator
    ** @param {Date} date - date to format
    ** @param {string} s - separator, default is /
    ** @returns {string} date formatted as DD/MM/YYYY with supplied separator
    */
    function formatDMY(date, s) {
      s = s || '/';
      function z(n){return (n<10?'0':'')+n}
      return [z(date.getDate()),z(date.getMonth()+1),
              date.getFullYear()].join(s); 
    }
    
    /* Create array of date ranges in DD.MM.YYYY-DD.MM.YYYY format
    ** @param {Array} data - array of date strings in DD.MM.YYYY format
    ** @returns {Array} array of range strings in DD.MM.YYYY-DD.MM.YYYY format
    */
    function createRanges(data) {
      var result = [];
      var previous;
      data.forEach(function(s, i) {
        var previous, previousNext, current, range;
        // If on first loop, create a range using first value
        if (i == 0) {
          result.push(s + '-' + s);
         
        // Otherwise, get end date of last range and add one day
        } else {
          previous = result[result.length-1].split('-')[1];
          previousNext = parseDMY(previous);
          previousNext.setDate(previousNext.getDate() + 1);
          previousNext = formatDMY(previousNext,'.');
          
          // If current date is same as previousNext, update range. 
          // Otherwise, start a new range
          if (s == previousNext) {
            range = result[result.length-1];
            result[result.length-1] = range.split('-')[0] + '-' + s;
    
          } else {
            result.push(s + '-' + s);
          }
        }
      });
      // Remove zero day ranges. Could do this by checking last range
      // when creating a new one but seems simpler to do it here
      result = result.filter(s=>!(s.split('-')[0] == s.split('-')[1]));
      return result;
    }
    
    console.log(createRanges(dates));

    Тем не менее, библиотека, как момент.js поможет с синтаксическим анализом, форматированием и арифметикой.

  4. То же, что сделано Leandro, но сделано для массива с объектами даты и с использованием момента.js

    function groupDates(dates) {
        const res = [];
        const isNextDay = (day, nextDay) => moment(day).add(1, 'day').isSame(nextDay, 'day');
        const format = "DD.MM.YYYY";
    
        let aux = moment(dates[0]).format(format) + "-";
        for (let i = 1; i < dates.length; i++) {
            if (!isNextDay(dates[i - 1], dates[i])) {
                aux += moment(dates[i - 1]).format(format);
                res.push(aux);
                aux = moment(dates[i]).format(format) + "-";
            }
        }
        aux += moment(dates[dates.length - 1]).format(format);
        res.push(aux);
        return res;
    }