Объединить массив дат, отсортированных в порядке возрастания, в массив диапазонов дат - PullRequest
0 голосов
/ 22 января 2020

У меня есть один массив дат, я хочу создать объект, содержащий начало и конец, проверяя даты продолжения. Пример.

dateArray = [
                "2020-01-22T00:00:00.000Z",
                "2020-01-23T00:00:00.000Z",
                "2020-01-28T00:00:00.000Z",
                "2020-01-29T00:00:00.000Z",
                "2020-01-30T00:00:00.000Z",
                "2020-01-31T00:00:00.000Z",
                "2020-02-01T00:00:00.000Z",
                "2020-02-02T00:00:00.000Z",
                "2020-02-03T00:00:00.000Z",
                "2020-02-04T00:00:00.000Z",
                "2020-02-05T00:00:00.000Z",
                "2020-02-06T00:00:00.000Z",
                "2020-02-07T00:00:00.000Z",
                "2020-02-16T00:00:00.000Z",
                "2020-02-17T00:00:00.000Z",
                "2020-02-18T00:00:00.000Z",
                "2020-02-19T00:00:00.000Z",
                "2020-02-20T00:00:00.000Z"
            ]

myRequirement = [{
    start: "2020-01-22T00:00:00.000Z",
    end: "2020-01-23T00:00:00.000Z"
  },
  {
    start: "2020-01-28T00:00:00.000Z",
    end: "2020-02-07T00:00:00.000Z"
  },
  {
    start: "2020-02-16T00:00:00.000Z",
    end: "2020-02-20T00:00:00.000Z"
  }
]

Я хочу сделать это используя node.js. Я попробовал это, используя несколько вложенных циклов. Сначала я запускаю l oop на главном массиве dateArray, затем проверяю, является ли это первой датой или нет, если это первая дата, затем сохраняю ее как дату начала первых объектов, затем в случае проверки следующей даты это следующая наибольшая дата предыдущей даты или нет.

let gapArray = [];
            let startEndObj = {};
            let tempStartDate;
            let tempEndDate;

            let tempNextDate;
            await asyncForEach(finalAvailablityDatesArrayOFi.availeblityDatesArray, async (availeblityDatesArrayOFi) => {
                console.log("availeblityDatesArrayOFi", availeblityDatesArrayOFi);

                if (!tempStartDate) {
                    console.log("In if");
                    startEndObj.startDate = availeblityDatesArrayOFi;
                    tempStartDate = availeblityDatesArrayOFi;
                    let oneDatePlus = new Date(availeblityDatesArrayOFi).setDate(new Date(availeblityDatesArrayOFi).getDate() + 1);
                    tempNextDate = new Date(oneDatePlus);
                    console.log("startEndObj", startEndObj);
                }
                else if (tempStartDate) {
                    console.log("in else");

                    if (new Date(availeblityDatesArrayOFi).getTime() == new Date(tempNextDate).getTime()) {
                        console.log("Do nothing!");
                        tempStartDate = availeblityDatesArrayOFi;
                        tempEndDate = availeblityDatesArrayOFi;
                        let oneDatePlus = new Date(availeblityDatesArrayOFi).setDate(new Date(availeblityDatesArrayOFi).getDate() + 1);
                        tempNextDate = new Date(oneDatePlus);
                    }
                    else {
                        startEndObj.endDate = new Date(tempEndDate);
                        gapArray.push(startEndObj);
                        tempStartDate = '';
                        tempEndDate = '';
                        startEndObj = {};
                    }
                }
            });

Спасибо!

Ответы [ 2 ]

1 голос
/ 23 января 2020

Вы должны быть осторожны с этим типом обработки, чтобы точно определить все бизнес-правила. Если временной компонент не должен учитываться, то его следует удалить, иначе при сравнении, скажем, с 2020-01-01T00: 00: 00 до 2020-01-02T012: 00: 00 вы получите разницу, превышающую 1 день, но не хочу, чтобы это воспринималось как начало нового диапазона.

По этой причине лог "1012 * разницы в днях" должен быть в отдельной функции, что также облегчает изменение библиотек дат, если Вы используете один. Разница в днях также подписана, поэтому убедитесь, что они переданы в правильном порядке.

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

let dateArray = [
  "2020-01-22T00:00:00.000Z",
  "2020-01-23T00:00:00.000Z",
  "2020-01-28T00:00:00.000Z",
  "2020-01-29T00:00:00.000Z",
  "2020-01-30T00:00:00.000Z",
  "2020-01-31T00:00:00.000Z",
  "2020-02-01T00:00:00.000Z",
  "2020-02-02T00:00:00.000Z",
  "2020-02-03T00:00:00.000Z",
  "2020-02-04T00:00:00.000Z",
  "2020-02-05T00:00:00.000Z",
  "2020-02-06T00:00:00.000Z",
  "2020-02-07T00:00:00.000Z",
  "2020-02-16T00:00:00.000Z",
  "2020-02-17T00:00:00.000Z",
  "2020-02-18T00:00:00.000Z",
  "2020-02-19T00:00:00.000Z",
  "2020-02-20T00:00:00.000Z"
];

// Simple difference in days function
function daysDiff(d0, d1) {
  return Math.round((d1 - d0) / 8.64e7);
}

let ranges = dateArray.reduce((acc, curr, i, arr) => {

  // If first date, initialise first object
  if (!acc.length) {
    acc.push({start: curr, end: curr});

  } else {
    let d0 = new Date(curr);
    let d1 = new Date(arr[i-1]);

    // If difference greater than 1 day, end previous range
    // and start a new range
    if (daysDiff(d1, d0) > 1) {
      acc[acc.length - 1].end = arr[i-1];
      acc.push({start: curr, end: curr});
    }
  }
  return acc;
}, []);

console.log(ranges);
1 голос
/ 22 января 2020

Выглядит как работа для Array.prototype.reduce().


Примечание: здесь и далее предполагается, что выполнены несколько предварительных условий:

  • элементы исходного массива являются допустимыми строками даты в формате ISO или другими, которые могут быть проанализированы конструктором new Date(), в противном случае должны быть приведены к одному из поддерживаемых форматов
  • элементы исходного массива отсортированы в порядке возрастания, в противном случае Array.prototype.sort() метод должен быть применен заранее
  • элементы массива не включают часть времени дня (или эта часть точно одинакова для всех элементов), в противном случае последовательные записи даты могут иметь различие, превышающее 864e5 миллисекунд (1 день) и требуется более сложное сравнение

Вы можете пройтись по своему массиву и сравнить текущие элементы с предыдущими / последующими, как только у вас будет разрыв, превышающий 1 день, вы sh Новый диапазон в результирующий массив или изменить дату окончания для последнего:

const src = ["2020-01-22T00:00:00.000Z","2020-01-23T00:00:00.000Z","2020-01-28T00:00:00.000Z","2020-01-29T00:00:00.000Z","2020-01-30T00:00:00.000Z","2020-01-31T00:00:00.000Z","2020-02-01T00:00:00.000Z","2020-02-02T00:00:00.000Z","2020-02-03T00:00:00.000Z","2020-02-04T00:00:00.000Z","2020-02-05T00:00:00.000Z","2020-02-06T00:00:00.000Z","2020-02-07T00:00:00.000Z","2020-02-16T00:00:00.000Z","2020-02-17T00:00:00.000Z","2020-02-18T00:00:00.000Z","2020-02-19T00:00:00.000Z","2020-02-20T00:00:00.000Z"],
     ranges = src.reduce((res,date,idx,self) => {
      const rangeStart = !idx || new Date(date) - new Date(self[idx-1]) > 864e5,
            rangeEnd = idx == self.length-1 || new Date(self[idx+1]) - new Date(date) > 864e5
      if(rangeStart) res.push({startdate:date,enddate:date}) 
      else if(rangeEnd) res[res.length-1]['enddate'] = date 
      return res
     }, [])
     
console.log(ranges)
.as-console-wrapper {min-height:100%}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...