如何用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方法实现,但不清楚如何展开日期范围并完成分组,请求解决方案。
实现思路
- 日期处理工具函数:
- 提取日期字符串中的
YYYY-MM-DD部分,统一日期格式 - 生成两个日期之间的所有日期数组,处理跨天展开的需求
- 提取日期字符串中的
- 遍历分组:
- 使用
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
相关产品推荐
相关产品推荐

