基于Microsoft Graph API的Outlook事件recurrence pattern日期生成纠错求助
修正relativeMonthly recurrence日期生成代码
问题分析
你的代码存在两个核心错误:
- 未将
pattern.index字符串转换为数值:直接用"third"这类字符串参与算术运算((nthOccurrence - 1) * 7)会导致计算逻辑失效。 dayName变量未定义:代码中引用了dayName但未从pattern.daysOfWeek中取值,导致星期几的索引计算错误。- (可选)未处理
index为"last"的特殊场景,也未考虑指定时区的日期转换。
修正后的代码
主逻辑部分
case "relativeMonthly": if (pattern.daysOfWeek && pattern.daysOfWeek.length > 0) { // 映射星期几到数字(周日=0,和JS Date.getDay()一致) const daysMap = { 'sunday': 0, 'monday': 1, 'tuesday': 2, 'wednesday': 3, 'thursday': 4, 'friday': 5, 'saturday': 6 }; // 映射index字符串到数值,last用-1标记 const indexMap = { 'first': 1, 'second': 2, 'third': 3, 'fourth': 4, 'last': -1 }; const targetDay = daysMap[pattern.daysOfWeek[0].toLowerCase()]; const nth = indexMap[pattern.index.toLowerCase()]; // 若需要时区支持,调用带时区的版本 const nextOccurrence = findNthDayOfMonth( newDate.getFullYear(), newDate.getMonth(), targetDay, nth ); // 时区版本调用: // const nextOccurrence = findNthDayOfMonthInTimeZone( // newDate.getFullYear(), // newDate.getMonth(), // targetDay, // nth, // pattern.range.recurrenceTimeZone // ); newDate = new Date(nextOccurrence); } else { newDate.setMonth(newDate.getMonth() + pattern.interval); } break;
核心工具函数(基础版)
function findNthDayOfMonth(year, month, dayOfWeek, nthOccurrence) { // 处理"last" occurrence的场景 if (nthOccurrence === -1) { // 获取当月最后一天 const date = new Date(year, month + 1, 0); // 调整到当月最后一个目标星期几 const diff = (dayOfWeek - date.getDay() + 7) % 7; if (diff !== 0) { date.setDate(date.getDate() - (7 - diff)); } return date; } // 处理first/second/third/fourth场景 let date = new Date(year, month, 1); // 找到当月第一个目标星期几 const firstDiff = (dayOfWeek - date.getDay() + 7) % 7; date.setDate(date.getDate() + firstDiff); // 偏移到第n个 occurrence date.setDate(date.getDate() + (nthOccurrence - 1) * 7); // 校验日期是否仍在当月(避免极端情况,比如2月不存在第5个周一) if (date.getMonth() !== month) { throw new Error(`Month ${month + 1} ${year} does not have a ${nthOccurrence}th ${getDayName(dayOfWeek)}`); } return date; } // 辅助函数:根据数字返回星期几名称 function getDayName(dayOfWeek) { const days = ['sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday']; return days[dayOfWeek]; }
时区支持版工具函数(适配India Standard Time等)
如果你需要严格按照recurrenceTimeZone计算日期,使用这个版本:
function findNthDayOfMonthInTimeZone(year, month, dayOfWeek, nthOccurrence, timeZone) { const formatter = new Intl.DateTimeFormat('en-US', { timeZone: timeZone, year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }); // 获取目标时区下的当月第一天 const firstDayUTC = new Date(year, month, 1); const parts = formatter.formatToParts(firstDayUTC); const tzYear = parseInt(parts.find(p => p.type === 'year').value); const tzMonth = parseInt(parts.find(p => p.type === 'month').value) - 1; const tzDay = parseInt(parts.find(p => p.type === 'day').value); let date = new Date(tzYear, tzMonth, tzDay); if (nthOccurrence === -1) { // 获取目标时区下的当月最后一天 const nextMonthFirst = new Date(tzYear, tzMonth + 1, 1); const lastDay = new Date(nextMonthFirst.getTime() - 86400000); // 减去一天的毫秒数 const diff = (dayOfWeek - lastDay.getDay() + 7) % 7; if (diff !== 0) { lastDay.setDate(lastDay.getDate() - (7 - diff)); } return lastDay; } const firstDiff = (dayOfWeek - date.getDay() + 7) % 7; date.setDate(date.getDate() + firstDiff); date.setDate(date.getDate() + (nthOccurrence - 1) * 7); if (date.getMonth() !== tzMonth) { throw new Error(`Month ${tzMonth + 1} ${tzYear} does not have a ${nthOccurrence}th ${getDayName(dayOfWeek)} in ${timeZone}`); } return date; }
验证示例
针对你提供的pattern(第三个周三):
- 2023年12月的第三个周三:20日(符合startDate)
- 2024年3月的第三个周三:20日
- 2024年6月的第三个周三:19日(此为正确日期,若你预期20日可能是时区或日期记忆偏差)
内容的提问来源于stack exchange,提问作者COdeingNinja
相关产品推荐
相关产品推荐

