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

基于Microsoft Graph API的Outlook事件recurrence pattern日期生成纠错求助

修正relativeMonthly recurrence日期生成代码

问题分析

你的代码存在两个核心错误:

  1. 未将pattern.index字符串转换为数值:直接用"third"这类字符串参与算术运算((nthOccurrence - 1) * 7)会导致计算逻辑失效。
  2. dayName变量未定义:代码中引用了dayName但未从pattern.daysOfWeek中取值,导致星期几的索引计算错误。
  3. (可选)未处理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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 11:47:15