【问题标题】:How could I get the the Nth Monday, Tuesday, etc. of every month between two dates using JavaScript我如何使用 JavaScript 在两个日期之间获得每个月的第 N 个星期一、星期二等
【发布时间】:2021-11-29 00:29:31
【问题描述】:

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

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

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

下面的 sn-p 是我按日期每月重复日期的函数,这适用于在开始日期和结束日期之间的任何一个月的 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
            });
        }
    }
}

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

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

【问题讨论】:

    标签: javascript json date


    【解决方案1】:

    要获得一个月中某一天的第 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))}`);
    });

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

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

    【讨论】:

      【解决方案2】:

      您能否仅获取每月第一天的星期几,然后从中计算出距离所需的星期几的天数。然后将 7 相加,直到得到所需的日期。

      例如:

      const startDate = new Date("2021-03-01"); // Mon Mar 01 2021
      const friday = 5;        // Friday is the 5th day of the week (Monday is 1)
      const weekOfMonth = 2;   // We want the 3rd week of the month (1st week is 0)
      
      // Start calculations
      const dayOfWeek = startDate.getUTCDay(); // 1
      const diff = friday - dayOfWeek;         // 4
      const dateOf3rdFriday = new Date(
          startDate.getUTCFullYear(),
          startDate.getUTCMonth(),
          startDate.getUTCDay() + diff + 7 * weekOfMonth
      ); // Fri Mar 19 2021
      

      在本月的最后一个星期五,您只需要做同样的事情,但相反。

      【讨论】:

      • 使用 UTC 的唯一原因是因为您以 new Date("2021-03-01") 开头。如果您从 new Date(2021,2,1) 这样的本地值开始,那么您可以使用所有本地方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-12
      • 1970-01-01
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多