如何使用 JavaScript 获取两个日期之间每个月的第 N 个星期一、星期二等

Cla*_*sco 3 javascript json date

我有一个程序,用户可以设置一个事件,包括开始日期、结束日期和事件应重复的重复周期,每周、每月按日期、每月按工作日和每年重复。用户创建事件后,它会保存在数据库中,并且该事件会显示在我的程序主页上的日历中。

到目前为止,我已经能够设计出每周重复日期、每月按日期重复日期和每年重复日期的算法,但不能设计每月按工作日重复日期的算法。我所说的“每月按工作日”是指在开始日期和结束日期占据的时间段内每月每个同一工作日重复一次的事件。

例如,在3月1日到11月1日之间每个月的第一个星期一重复的事件,3月1日是3月的第一个星期一,所以我想生成一个日期是4月的第一个星期一,即4月5日, 3 月至 11 月之间的每个月,依此类推。

下面的代码片段是我按日期每月重复日期的函数,适用于在开始日期和结束日期之间的任何一个月的每 15 日重复一次的事件。

function repeatEventMonthly(jsonArray, num){

//First I get the start date and end date as strings on a JSON, I separate
//them by the "/" and then use the individual parts to construct two Date Objects

var split = jsonArray[num].Fecha.split("/");
var split2 = jsonArray[num].fechaFin.split("/");

var dd = split[1];
var mm = split[0];
var yy = split[2];

var dd2 = split2[1];
var mm2 = split2[0];
var yy2 = split2[2];

var starDate = new Date();
var endDate = new Date();

starDate.setFullYear(yy);
starDate.setMonth(mm-1);
starDate.setDate(dd);
endDate.setFullYear(yy2);
endDate.setMonth(mm2-1);
endDate.setDate(dd2);

//the variable top means how many days are between the startDate and endDate.
//I use a function that calculates this number

var top = getDaysInDates(starDate, endDate);

if (jsonArray[num].tipoRepeticion == "2") {

 //the attribute "tipoRepeticion" in my JSON object lets me know what type of
 //repetition the event must be set, 2 means Monthly by Weekday and 3 is Monthly by Date

}else if(jsonArray[num].tipoRepeticion == "3"){

    //If the event has repetition type 3, then inside this for loop I generate a new date
    //which I create with the value of the startDate and then I add the index number in the for
    //loop cycle, meaning that if the startDate is March 3, the in index 1 is March 4, Index 2
    //is March 5 and so on, then with an If statement I check that if the date on the
    //generated date object is the same as the date of the startDate, I push the date to  
    //another JSON array that I use to display the dates on the calendar.

    for (let index = 0; index < top; index++) {
        let sd = new Date(starDate);
        sd.setDate(sd.getDate()+index);
        if (sd.getDate() == starDate.getDate()) {
            let str = ((sd.getMonth()+1) + "/" + sd.getDate() + "/" + sd.getFullYear()).toString();
            eventMen.push({

                // the function "construcDates" helps me create a valid String for my program
                // to display at the user.

                date: constructDates(str, 0, jsonArray[num].tipoRepeticion),
                title: jsonArray[num].titulo,
                descripcion: jsonArray[num].descripcion,
                tipo: jsonArray[num].tipo,
                tipoRepeticion : jsonArray[num].tipoRepeticion
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,此函数有效地生成相隔一个月但在同一日期的事件,这意味着如果我的事件从 3 月 3 日开始,并于 12 月 3 日结束,那么在我的日历中,它会在 4 月 3 日、5 月 3 日、6 月 3 日、7 月 3 日显示相同的事件...一直到11月3日。这个方法可能比我需要的更复杂,但我仍在学习 JavaScript,所以这就是我想出的方法。

然而,尽管已经解决了其他类型的重复日期的逻辑,(每周、每月按日期和每年)每月按工作日重复日期变得相当困难,因为每个月的天数并不相同,例如,我不能只将每个月的 30 或 31 天加起来,并希望日期落在同一个“每月的第一个星期一”。我想问是否有人对如何计算这个难题有任何建议或解决方案,还值得指出的是,“任何月份的第一个星期一”的示例并不是按月重复日期的唯一可能类型,它也是可以是每个月的第二个星期二或最后一个星期五。

Rob*_*obG 5

要获取该月中某一天的第 n 个实例,请创建该月第一天的日期,移至所需日期的第一个实例,然后添加 (n-1) 周的天数,例如

/* Get nth instance of a particular weekday in a month
 *
 * @param {number|string} nth - instance of day, 1 to 4
 * @param {number|string} day - day of week, Sun 0, Mon 1, etc.
 * @param {Date} month - any date in month to get day of
 * @returns {Date} that is nth instance of day in month
*/
function getNthDayInMonth(nth, day, month) {
  // Create new date for 1st of month
  let d = new Date(month.getFullYear(), month.getMonth());
  // Move to first instance of day in month and 
  // add (n - 1) weeks
  d.setDate(1 + (7 - d.getDay() + day)%7 + (nth - 1)*7);
  return d;
}

// Formater
let f = (d) => new Intl.DateTimeFormat('en-GB', {
  weekday:'short',
  day:'2-digit',
  month:'short',
  year: 'numeric'
}).format(d);

// Examples
[[1,1,new Date(2021,11),'1st Mon in Dec 2021'],
 [3,3,new Date(2022, 0),'3rd Wed in Jan 2022'],
 [4,1,new Date(2022, 1),'4th Mon in Feb 2022'],
 [4,2,new Date(2022, 1),'4th Tue in Feb 2022'],
 [4,3,new Date(2022, 1),'4th Wed in Feb 2022'],
 [1,3,new Date(2022, 5),'1st Wed in Jun 2022'],
 [5,5,new Date(2022,11),'5th Fri in Dec 2022']
].forEach(a => {
  let [n,d,m,note] = a;
  console.log(`${note}: ${f(getNthDayInMonth(n,d,m))}`);
});
Run Code Online (Sandbox Code Playgroud)

一个月中的每一天总是至少有 4 个实例,某些日子最多有 5 个实例(例如,2022 年 1 月有 5 个星期六、星期日和星期一)。第n 个参数可能限制为 4,或者如果允许第 5 个实例,则将其限制为 5,然后检查结束月份是否与开始月份相同。如果不是,则抛出错误或仅返回未定义。

要获取两个日期之间月份的所有第 n 天,请循环遍历月份以获取第 n 个实例,并删除开始之前或结束之后的所有日期。