You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js中如何排除用户选定期限内不在指定区间的日期?

问题:排除用户日期范围内不在场馆可用区间的日期

我有一个包含多个场馆可用日期区间的数组venueTimings,以及用户选择的一组起止日期范围。需要从用户选择的日期范围中,排除所有不属于venueTimings中任意一个区间的日期。

场馆可用日期区间数组:

const venueTimings = [
  {
    start_date: '2024-07-01T00:00:00.000Z',
    end_date: '2024-07-31T00:00:00.000Z'
  },
  {
    start_date: '2024-08-01T00:00:00.000Z',
    end_date: '2024-08-31T00:00:00.000Z'
  },
  {
    start_date: '2024-10-01T00:00:00.000Z',
    end_date: '2024-10-31T00:00:00.000Z'
  }
];

用户选择的日期范围:

const userStart = '2024-07-01T00:00:00.000Z';
const userEnd = '2024-10-31T00:00:00.000Z';

当前尝试的代码(未达预期):

if (moment(start_date) < moment(venueTiming.start_date)) {
  for (let d = moment(start_date); d.diff(venueTiming.start_date, 'days') <= 0; d.add(1, 'days')) {
    let date = d.format('YYYY-MM-DD');
    excluded_dates.push({ date, reason: 'missing-venue-time' });
    blocked_dates.push(date);
  }
}
if (moment(venueTiming.end_date) < moment(end_date)) {
  for (let d = moment(venueTiming.end_date); d.isBefore(moment(end_date)); d.add(1, 'days')) {
    const date = d.format('YYYY-MM-DD');
    if (d.format('dddd') === day) {
      excluded_dates.push({ date, reason: 'missing-venue-time' });
      blocked_dates.push(date);
    }
  }
}

存在的问题:上述代码仅能处理单个场馆区间与用户区间的前后差异,无法覆盖多个场馆区间之间的空白(比如示例中的9月份),也未遍历所有场馆区间做完整校验,导致无法准确排除所有不符合条件的日期。


解决方案

方法1:遍历用户日期范围逐天判断

逻辑直观,适合日期范围较小的场景:

const moment = require('moment');

const venueTimings = [
  { start_date: '2024-07-01T00:00:00.000Z', end_date: '2024-07-31T00:00:00.000Z' },
  { start_date: '2024-08-01T00:00:00.000Z', end_date: '2024-08-31T00:00:00.000Z' },
  { start_date: '2024-10-01T00:00:00.000Z', end_date: '2024-10-31T00:00:00.000Z' }
];
const userStart = moment('2024-07-01T00:00:00.000Z');
const userEnd = moment('2024-10-31T00:00:00.000Z');

const excludedDates = [];
const blockedDates = [];

// 遍历用户选择的每一天
for (let currentDate = moment(userStart); currentDate.isSameOrBefore(userEnd); currentDate.add(1, 'days')) {
  const formattedDate = currentDate.format('YYYY-MM-DD');
  // 判断当前日期是否在任意场馆可用区间内
  const isInVenueRange = venueTimings.some(timing => {
    const venueStart = moment(timing.start_date);
    const venueEnd = moment(timing.end_date);
    return currentDate.isBetween(venueStart, venueEnd, 'day', '[]'); // 包含起止日期
  });

  if (!isInVenueRange) {
    excludedDates.push({ date: formattedDate, reason: 'missing-venue-time' });
    blockedDates.push(formattedDate);
  }
}

console.log('排除的日期:', excludedDates);
console.log('被阻止的日期列表:', blockedDates);

方法2:先计算差集区间再生成日期

通过计算空白区间减少遍历次数,效率更高,适合大范围日期场景:

const moment = require('moment');

const venueTimings = [
  { start_date: '2024-07-01T00:00:00.000Z', end_date: '2024-07-31T00:00:00.000Z' },
  { start_date: '2024-08-01T00:00:00.000Z', end_date: '2024-08-31T00:00:00.000Z' },
  { start_date: '2024-10-01T00:00:00.000Z', end_date: '2024-10-31T00:00:00.000Z' }
];
const userStart = moment('2024-07-01T00:00:00.000Z');
const userEnd = moment('2024-10-31T00:00:00.000Z');

// 先将场馆区间按开始日期排序,避免顺序混乱导致漏判
const sortedVenueTimings = [...venueTimings].sort((a, b) => moment(a.start_date).valueOf() - moment(b.start_date).valueOf());

const excludedIntervals = [];
let prevEnd = moment(userStart);

// 遍历场馆区间,找出中间的空白区间
for (const timing of sortedVenueTimings) {
  const venueStart = moment(timing.start_date);
  const venueEnd = moment(timing.end_date);

  // 当前场馆区间开始晚于上一个区间结束,说明存在空白
  if (venueStart.isAfter(prevEnd)) {
    excludedIntervals.push({
      start: moment(prevEnd),
      end: moment(venueStart).subtract(1, 'days')
    });
  }

  // 更新上一个区间的结束日期为当前场馆区间的结束日期(取较大值,兼容重叠区间)
  if (venueEnd.isAfter(prevEnd)) {
    prevEnd = venueEnd;
  }
}

// 检查用户区间结束日期是否晚于最后一个场馆区间的结束日期
if (userEnd.isAfter(prevEnd)) {
  excludedIntervals.push({
    start: moment(prevEnd).add(1, 'days'),
    end: moment(userEnd)
  });
}

// 生成所有排除区间内的日期
const excludedDates = [];
const blockedDates = [];

for (const interval of excludedIntervals) {
  for (let d = moment(interval.start); d.isSameOrBefore(interval.end); d.add(1, 'days')) {
    const formattedDate = d.format('YYYY-MM-DD');
    excludedDates.push({ date: formattedDate, reason: 'missing-venue-time' });
    blockedDates.push(formattedDate);
  }
}

console.log('排除的日期:', excludedDates);
console.log('被阻止的日期列表:', blockedDates);

关键说明

  • 方法1逻辑简单,适合小范围日期;方法2通过计算空白区间减少遍历次数,效率更优。
  • moment.isBetween的第四个参数'[]'表示包含起止日期,确保边界日期被正确判断。
  • 对场馆区间排序是必要步骤,避免因区间顺序混乱导致空白区间漏判。

内容的提问来源于stack exchange,提问作者Jaskaran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 11:14:55