计算日期间隔内的日期

Count dates within date intervals

我有一个包含日期和时间的数组 abc。我需要将其转换为 1 天的时隙,其限制由 startDateendDate 确定,其中 'x' 包含时隙,'y' 包含这些时隙中的出现次数。如何根据间隔获取 abc 中的出现次数并根据日期间隔正确映射它?

const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];
const startDate = '2021-07-05'; 
const endDate = '2021-11-05';
const res = [{x: '2021-07-05 - 2021-08-05' , y: '1' },{x: '2021-08-05 - 2021-09-05' , y: '2' }, {x: '2021-09-05 - 2021-10-05' , y: '1' },{x: '2021-10-05 - 2021-11-05' , y: '0' }];
console.log(res);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

这可能是实现所需 objective:

的一种可能解决方案

代码段

请查看 countWithinLimits 方法,其中包含解决方案的重要部分。

const data = [
  '2021-07-05T00:53:44.953Z', '2021-07-04T00:53:44.953Z', 
  '2021-07-14T00:53:44.953Z', '2021-07-12T00:53:44.953Z', 
  '2021-07-06T00:53:44.953Z', '2021-07-05T00:53:44.953Z', 
  '2021-07-07T00:53:44.953Z', '2021-07-11T00:53:44.953Z', 
  '2021-07-08T00:53:44.953Z', '2021-07-10T00:53:44.953Z', 
  '2021-07-09T00:53:44.953Z', '2021-07-07T00:53:44.953Z', 
  '2021-07-10T00:53:44.953Z', '2021-07-05T00:53:44.953Z', 
  '2021-07-11T00:53:44.953Z', '2021-07-07T00:53:44.953Z', 
];
const startDate = '2021-07-05';
const endDate = '2021-07-11';

// expected result structure for reference
const expectedResult = [
  {x: '2021-07-05 - 2021-07-06', y: '1' },
  {x: '2021-07-06 - 2021-07-07', y: '2' },
  {x: '2021-07-07 - 2021-07-08', y: '1' },
  {x: '2021-07-08 - 2021-07-09', y: '0' }
];

const countWithinLimits = (st, en, arr = data) => {

  // helper function to add 'i' days to given 'dt'
  const addDays = (dt, i) => {
    const nx = new Date(dt);
    return (
        (
        new Date(nx.setDate(nx.getDate() + i))
        ).toISOString().split('T')[0]
    );
  };
  
  // transform 'dt' into look like 'x' in the expected result
  const transformToKey = dt => (`${dt} - ${addDays(dt, 1)}`);
  
  // set constants for start and end dates
  const stDate = new Date(st), enDate = new Date(en);
  
  // first determine the number of slots
  // (each will be 1-day duration, from st till en)
  const numDays = (
    Math.ceil(
      Math.abs(enDate - stDate) / (1000 * 60 * 60 * 24)
    )
  );
  
  // next, obtain an array with the slots
  // something like this: ['2021-07-05 - 2021-07-06', ....]
  const slots = (
    [...Array(numDays).keys()]
    .map(i => addDays(st, i))
    .map(d => transformToKey(d))
  );
  
  // generate an object with props as the slots and values as zeroes
  // like this: { '2021-07-05 - 2021-07-06': 0, ....}
  const slotObj = slots.reduce(
    (fin, itm) => ({...fin, [itm]: 0}),
    {}
  );
  
  // iterate through the data (arr)
  // find the slot in which a given date fits
  // and add 1 to the counter, if the slot is found in slotObj
  // do not count the date if it doesn't match any slots
  const countPerSlot = arr.reduce(
    (fin, itm) => ({
        ...fin,
      ...(
        [transformToKey(itm.split('T')[0])] in fin
        ? {
            [transformToKey(itm.split('T')[0])]: (
            fin[transformToKey(itm.split('T')[0])] + 1
          )
        }
        : {}
      )
    }),
    {...slotObj}
  );
  
  // finally, transform the countPerSlot object 
  // into the expected result array
  return (
    Object.entries(countPerSlot)
    .map(
      ([k, v]) => ({ x: k, y: v})
    )
  );
};

console.log(countWithinLimits(startDate, endDate));

说明

虽然上面code-snippet中有评论in-line,但如果有什么具体的地方需要更详细的解释,下面的'comments'可以用来通知和这个答案可能会更新更多细节。

big-picture的思路是这样的:

  • 将解决方案分成不同的 smaller-parts
  • 首先,生成 time-slots(长度为 1 天)
  • 接下来,创建一个对象,其中 props 是句点(如 2021-07-05 - 2021-07-06
  • 现在,遍历数据并递增对应于日期适合的 prop 的计数器
  • 最后,将对象转换为与预期结果匹配的数组([ {x : '2021-07-05 - 2021-07-06', y: '2' }, .... ])

根据我的理解,我根据您在问题中提供的 startend 日期创建了一个简单的工作演示 :

const abc = ['2021-09-05T00:53:44.953Z', '2021-08-05T05:08:10.950Z', '2022-03-05T00:53:40.951Z'];

const startDate = '2021-07-05'; 
const endDate = '2021-11-05';

function countDates(inputArray, startDate, endDate) {
    let count = 0;
  const dateArray = abc.map((item) => new Date(item.split("T")[0]).getTime());

  dateArray.forEach((dayTime) => {
    if(dayTime >= new Date(startDate).getTime() && dayTime <= new Date(endDate).getTime()) {
      count ++;
    }
  });
  
  return [{x: `${startDate} - ${endDate}`, y: count}];
}

console.log(countDates(abc, startDate, endDate));

注意: 我假设您必须一次获取一次介于 startDateendDate 之间的范围。