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

如何用JS按日期范围分组对象数组并转换为日程格式?

日历数据按日期分组展开解决方案

问题描述

现有如下日历数据:

const calendarData = [
  {
    customerName: "Mark",
    startDatetime: "2022-08-10T17:10:11.000+0000",
    endDatetime: "2022-08-12T17:10:55.000+0000",
    description: 'Mark Description'
  },
  {
    customerName: "Tristan",
    startDatetime: null,
    endDatetime: "2022-08-10T10:10:55.000+0000",
    description: 'Tristan Description'
  },
  {
    customerName: "Andrew",
    startDatetime: "2022-08-14T17:10:11.000+0000",
    endDatetime: null,
    description: 'Andrew Description'
  },
  {
    customerName: "Kevin",
    startDatetime: "2022-08-10T17:10:11.000+0000",
    endDatetime: "2022-08-11T17:10:55.000+0000",
    description: 'Kevin Description'
  }
];

需要将其转换为按日期分组的日程格式,满足:

  • 若startDatetime和endDatetime跨超过1天,需展开所有包含的日期
  • 若startDatetime为null,仅取endDatetime对应的日期;反之亦然

预期输出:

const expected = {
  '2022-08-10': [
    {
      customerName: 'Mark',
      description: 'Mark Description'
    },
    {
      customerName: 'Tristan',
      description: 'Tristan Description'
    },
    {
      customerName: "Kevin",
      description: 'Kevin Description'
    }
  ],
  '2022-08-11': [
    {
      customerName: 'Mark',
      description: 'Mark Description'
    },
    {
      customerName: "Kevin",
      description: 'Kevin Description'
    }
  ],
  '2022-08-12': [
    {
      customerName: 'Mark',
      description: 'Mark Description'
    },
  ],
  '2022-08-14': [
    {
      customerName: 'Andrew',
      description: 'Andrew Description'
    },
  ]
}

用户尝试用reduce方法实现,但不清楚如何展开日期范围并完成分组,请求解决方案。

实现思路

  1. 日期处理工具函数:
    • 提取日期字符串中的YYYY-MM-DD部分,统一日期格式
    • 生成两个日期之间的所有日期数组,处理跨天展开的需求
  2. 遍历分组:
    • 使用reduce遍历原始数据,对每个条目确定其覆盖的所有日期
    • 将每个条目信息添加到对应日期的数组中

完整代码实现

// 提取日期字符串的YYYY-MM-DD部分
function getDateStr(datetimeStr) {
  if (!datetimeStr) return null;
  return datetimeStr.split('T')[0];
}

// 生成startDate到endDate之间的所有日期(包含两端)
function getDateRange(startDateStr, endDateStr) {
  const dates = [];
  const start = new Date(startDateStr);
  const end = new Date(endDateStr);
  
  let current = new Date(start);
  while (current <= end) {
    dates.push(current.toISOString().split('T')[0]);
    current.setDate(current.getDate() + 1);
  }
  return dates;
}

// 处理日历数据并分组
const result = calendarData.reduce((acc, item) => {
  let dateRange = [];
  
  // 处理start或end为null的情况
  if (!item.startDatetime) {
    dateRange = [getDateStr(item.endDatetime)];
  } else if (!item.endDatetime) {
    dateRange = [getDateStr(item.startDatetime)];
  } else {
    // 处理跨天情况
    const startDate = getDateStr(item.startDatetime);
    const endDate = getDateStr(item.endDatetime);
    dateRange = getDateRange(startDate, endDate);
  }
  
  // 将当前条目添加到每个对应日期的数组中
  dateRange.forEach(date => {
    if (!acc[date]) {
      acc[date] = [];
    }
    acc[date].push({
      customerName: item.customerName,
      description: item.description
    });
  });
  
  return acc;
}, {});

console.log(result);

代码说明

  • getDateStr:从ISO格式的时间字符串中提取日期部分,忽略时间和时区信息
  • getDateRange:通过循环递增日期,生成两个日期之间的所有日期字符串数组
  • reduce遍历逻辑:
    • 先根据条目是否有startDatetime或endDatetime确定覆盖的日期范围
    • 对每个日期,初始化数组(如果不存在),然后添加当前条目的简化信息(仅保留customerName和description)

运行代码后,输出结果与预期完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:54:16