在 JS 中使用 date-fns 每 15 分钟填充缺失的时间间隔

Filling missing time intervals for every 15 minutes using date-fns in JS

假设我有一个对象数组,每个对象代表某个时间和相应的价格值:

const prices = [
  {
    price_time: '2021-10-13T16:30:00+00:00',
    price: 3.5,
  },
  {
    price_time: '2021-10-13T18:15:00+00:00"',
    price: 5,
  },
  {
    price_time: '2021-10-13T19:15:00+00:00"',
    price: 6.5,
  },
];

现在假设我需要以 15 分钟的间隔输出 prices 数组第一个和最后一个元素的 price_time 值之间每小时的所有价格列表。

定义的 16:3018:1519:15 时间的结果间隔列表将是:

[
  { price_time: '2021-10-13T16:30:00.000Z', price: 3.5 }, // first elem in the prices array
  { price_time: '2021-10-13T16:45:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:00:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:15:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:30:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:45:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T18:00:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T18:15:00.000Z', price: 5 }, // second elem in the prices array
  { price_time: '2021-10-13T18:30:00.000Z', price: 5 },
  { price_time: '2021-10-13T18:45:00.000Z', price: 5 },
  { price_time: '2021-10-13T19:00:00.000Z', price: 5 },
  { price_time: '2021-10-13T19:15:00.000Z', price: 6.5 } // last elem in the prices array
]

实现此目标的最佳方法是什么?我一直在尝试通过迭代数组值来完成它,获取每两个元素之间的小时数,然后填写 00:0000:1500:3000:45 间隔:

const _ = require('date-fns');

const prices = [
  { price_time: '2021-10-13T16:30:00+00:00', price: 3.5 },
  { price_time: '2021-10-13T18:15:00+00:00',price: 5 },
  { price_time: '2021-10-13T19:15:00+00:00', price: 6.5 },
];

function addMissingIntervals() {
  const allIntervals = [];
  prices.forEach((item, index) => {
    if (index !== prices.length - 1) { // if this isn't the last loop item
      const start = _.parseISO(item.price_time); // the datetime of the current loop item
      const end = _.parseISO(prices[index + 1].price_time); // the datetime of the next loop item
      const allHours = _.eachHourOfInterval({ start: start, end: end }); // all the hours between these two
      allHours.map((hour) => {
        allIntervals.push({ price_time: hour, price: item.price }) // insert the start of the hour
        allIntervals.push(
          ...[15, 30, 45].map((t) => { // for each hour, add 15m, 30m & 45m
            return { price_time: _.addMinutes(hour, t), price: item.price };
          }),
        );
      });
    }
  });
  // Adding the last item from `prices` as well
  allIntervals.push(prices[prices.length - 1]);
  return allIntervals;
}

console.log(addMissingIntervals());

然而,后者的结果包括所有时间的所有时间间隔,包括 start/end 日期之前或之后的时间间隔:

[
  { price_time: '2021-10-13T16:00:00.000Z', price: 3.5 }, // should not be included
  { price_time: '2021-10-13T16:15:00.000Z', price: 3.5 }, // should not be included
  { price_time: '2021-10-13T16:30:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T16:45:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:00:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:15:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:30:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T17:45:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T18:00:00.000Z', price: 3.5 },
  { price_time: '2021-10-13T18:15:00.000Z', price: 3.5 }, // should not be included
  { price_time: '2021-10-13T18:30:00.000Z', price: 3.5 }, // should not be included
  { price_time: '2021-10-13T18:45:00.000Z', price: 3.5 }, // should not be included
  { price_time: '2021-10-13T18:00:00.000Z', price: 5 }, // should not be included
  { price_time: '2021-10-13T18:15:00.000Z', price: 5 },
  { price_time: '2021-10-13T18:30:00.000Z', price: 5 },
  { price_time: '2021-10-13T18:45:00.000Z', price: 5 },
  { price_time: '2021-10-13T19:00:00.000Z', price: 5 },
  { price_time: '2021-10-13T19:15:00.000Z', price: 5 }, // should not be included
  { price_time: '2021-10-13T19:30:00.000Z', price: 5 }, // should not be included
  { price_time: '2021-10-13T19:45:00.000Z', price: 5 }, // should not be included
  { price_time: '2021-10-13T19:15:00.000Z', price: 6.5 }
]

我设法通过修改 this answer 解决了这个问题(它使用 moment.js 而不是 date-fns)。

基本上,我在每两个日期之间有一个循环 运行,将每个循环项目的时间四舍五入到最接近的 15 分钟,并为该间隔分配正确的价格。原始价格数组中的最后一项被忽略并在循环终止后添加到结果数组中:

const _ = require('date-fns');

const prices = [
  { price_time: '2021-10-13T16:30:00+00:00', price: 3.5 },
  { price_time: '2021-10-13T18:15:00+00:00', price: 5 },
  { price_time: '2021-10-13T19:15:00+00:00', price: 6.5 },
];

function intervalsGroup(startDate, endDate, price) {
  // Round to the nearest 15
  let current = _.setMinutes(startDate, Math.ceil(_.getMinutes(startDate) / 15) * 15);
  let group = [];
  while (endDate > current) {
    group.push({ price_time: current, price: price })
    current = _.addMinutes(current, 15);
  }
  return group;
}

function addMissingIntervals() {
  const allIntervals = [];
  prices.forEach((item, index) => {
    if (index !== prices.length - 1) { // if this isn't the last loop item
      const start = _.parseISO(item.price_time); // the datetime of the current loop item
      const end = _.parseISO(prices[index + 1].price_time); // the datetime of the next loop item
      allIntervals.push(...intervalsGroup(start, end, item.price)); // generate the 15m intervals between these two days
    }
  });
  allIntervals.push(prices[prices.length - 1]);
  return allIntervals;
}

console.log(addMissingIntervals());