【问题标题】:Add Working Days to a Date Using JavaScript使用 JavaScript 将工作日添加到日期
【发布时间】:2017-04-05 23:06:49
【问题描述】:

如何使用 JavaScript 添加工作日(即周一至周五)在必要时自动添加周末?

因此,如果我要在今天(2016 年 11 月 22 日星期二)加上 5 个工作日,结果应该是“2016 年 11 月 29 日星期二”而不是“2016 年 11 月 27 日星期日”。

【问题讨论】:

    标签: javascript


    【解决方案1】:

    可以使用DatesetDate 函数(结合getDate)在日期上添加天数,即-

    var myDate = new Date(); // Tue 22/11/2016
    myDate.setDate(myDate.getDate() + 3); // Fri 25/11/2016
    

    因此,一旦您计算出工作日期间的周末天数,您就可以将其和所需的工作日数添加到开始日期以获得最终日期。

    这个功能应该可以工作,但显然这不会考虑到国定假日 -

    function addWorkDays(startDate, days) {
        if(isNaN(days)) {
            console.log("Value provided for \"days\" was not a number");
            return
        }
        if(!(startDate instanceof Date)) {
            console.log("Value provided for \"startDate\" was not a Date object");
            return
        }
        // Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
        var dow = startDate.getDay();
        var daysToAdd = parseInt(days);
        // If the current day is Sunday add one day
        if (dow == 0)
            daysToAdd++;
        // If the start date plus the additional days falls on or after the closest Saturday calculate weekends
        if (dow + daysToAdd >= 6) {
            //Subtract days in current working week from work days
            var remainingWorkDays = daysToAdd - (5 - dow);
            //Add current working week's weekend
            daysToAdd += 2;
            if (remainingWorkDays > 5) {
                //Add two days for each working week by calculating how many weeks are included
                daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
                //Exclude final weekend if remainingWorkDays resolves to an exact number of weeks
                if (remainingWorkDays % 5 == 0)
                    daysToAdd -= 2;
            }
        }
        startDate.setDate(startDate.getDate() + daysToAdd);
        return startDate;
    }
    
    //And use it like so (months are zero based)
    var today = new Date(2016, 10, 22);
    today = addWorkDays(today, 5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)
    

    它也可以添加到Date原型中-

    Date.prototype.addWorkDays = function (days) {
        if(isNaN(days)) {
            console.log("Value provided for \"days\" was not a number");
            return
        }
    
        // Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
        var dow = this.getDay();
        var daysToAdd = parseInt(days);
        // If the current day is Sunday add one day
        if (dow == 0) {
            daysToAdd++;
        }
        // If the start date plus the additional days falls on or after the closest Saturday calculate weekends
        if (dow + daysToAdd >= 6) {
            //Subtract days in current working week from work days
            var remainingWorkDays = daysToAdd - (5 - dow);
            //Add current working week's weekend
            daysToAdd += 2;
            if (remainingWorkDays > 5) {
                //Add two days for each working week by calculating how many weeks are included
                daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
                //Exclude final weekend if the remainingWorkDays resolves to an exact number of weeks
                if (remainingWorkDays % 5 == 0)
                    daysToAdd -= 2;
            }
        }
        this.setDate(this.getDate() + daysToAdd);
    };
    
    //And use it like so (months are zero based)
    var today = new Date(2016, 10, 22)
    today.addWorkDays(5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)
    

    【讨论】:

    • 对于原型,我使用了return this.addDays(daysToAdd); 而不是this.setDate(this.getDate() + daysToAdd);,因为它更类似于原生Date.prototype.addDays 的工作方式。
    • @CSquared 原生 Date.prototype.addDays?我不知道原生的 addDays 方法,并且它没有记录在 MDN - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 上;您确定它没有被您的解决方案中的另一个 JS 文件添加吗?
    • 我的立场是正确的,它不是原生的。就我而言,它来自 Kendo UI 库。我希望它是原生的。
    【解决方案2】:

    我认为你可以使用moment-business-days

    例子:

    // 22-11-2016 is Tuesday, DD-MM-YYYY is the format 
    moment('22-11-2016', 'DD-MM-YYYY').businessAdd(5)._d // Tue Nov 29 2016 00:00:00 GMT-0600 (CST) 
    

    【讨论】:

      【解决方案3】:

      如果是添加几天,而不是几千天,那么这更容易且更具可读性:

      const currentDate = new Date('2021-11-18');
      console.log(currentDate.toString()); // "Thu Nov 18 2021 00:00:00 GMT+0000"
      
      const numToAdd = 5;
      
      for (let i = 1; i <= numToAdd; i++) {
        currentDate.setDate(currentDate.getDate() + 1);
        if (currentDate.getDay() === 6) {
          currentDate.setDate(currentDate.getDate() + 2);
        }
        else if (currentDate.getDay() === 0) {
          currentDate.setDate(currentDate.getDate() + 1);
        }
      }
      
      console.log(currentDate.toString()); // "Thu Nov 25 2021 00:00:00 GMT+0000"
      

      【讨论】:

      • 我认为这是最好的解决方案,它更直接且更易于理解。我稍微修改了你的代码,马克,希望没问题。
      【解决方案4】:

      const date = new Date('2000-02-02')
      const daysToAdd = mapToWorkdays(date, 37)
      
      date.setUTCDate(date.getUTCDate() + daysToAdd)
      
      console.log( date.toISOString().split('T')[0] )
      // prints 2000-03-24
      
      /**
       * @param {Date} date starting date
       * @param {number} add number of workdays to add
       * @return {number} total number of days to add to reach correct date
       */
      function mapToWorkdays(date, add) {
        const wd = weekday(date)
        
        let r = Math.trunc(add / 5) * 2
        const rem = add % 5
      
        if (wd > 4) r += (6-wd)
        else if (wd+rem > 4) r += 2
      
        return add + r
      }
      
      /**
       * @param {Date} date
       * @return {number} day of the week in range of 0..6 (monday..sunday)
       */
      function weekday(date) { return (date.getUTCDay()+ 6) % 7 }

      【讨论】:

      • 我认为这个解决方案是不正确的。对于周六和周日,当 add 参数是 5 的倍数时,mapToWorkdays 的结果不正确。我与 Excel 返回的结果进行了比较,确认这些具体结果是错误的。我已将 if (wd > 4) r += (6-wd) 替换为 if (wd > 4) { r += (6 - wd) if (rem === 0) r-= 2 }纠正这一点。在这里查看jsfiddle.net/Roebie/vx2prqj0/16 早期的解决方案更错误,但我没有花时间修复它们。
      • @Roebie 我认为唯一的问题是它应该是r += (7 - wd)。如果您从 sat/sun 调用该函数并传递 add:0,则结果仍应在星期六返回 2,在星期日返回 1。第一个 if 实际上是在说:“如果我们在周末,请将所有内容调整为一周的第一天(a.k.a 0)”。并且 else-if 说:“如果我们在工作日,并且 add%5 我们将在周末结束,我们应该再增加两天”
      【解决方案5】:

      更新了上面的脚本,如果给出负数,也会减去工作日...

      function addWorkDays(startDate, days) {
          var isAddingDays = (days > 0);
          var isDaysToAddMoreThanWeek = (days > 5 || days < -5);
      
          if (isNaN(days)) {
              console.log("Value provided for \"days\" was not a number");
              return
          }
          if (!(startDate instanceof Date)) {
              console.log("Value provided for \"startDate\" was not a Date object");
              return
          }
          var dow = startDate.getDay();
          var daysToAdd = parseInt(days);
      
          if ((dow === 0 && isAddingDays) || (dow === 6 && !isAddingDays)) {
              daysToAdd = daysToAdd + (1 * (isAddingDays ? 1 : -1));
          } else if ((dow === 6 && isAddingDays) || (dow === 0 && !isAddingDays)) {
              daysToAdd = daysToAdd + (2 * (isAddingDays ? 1 : -1));
          }
      
          if (isDaysToAddMoreThanWeek) {
              daysToAdd = daysToAdd + (2 * (Math.floor(days / 5)));
      
              if (days % 5 != 0)
                  daysToAdd = daysToAdd + (2 * (isAddingDays ?  -1 : 1));
          }
      
          startDate.setDate(startDate.getDate() + daysToAdd);
          var newDate = moment(startDate).format('MM/DD/YYYY');
          return newDate;
      }
      

      【讨论】:

      • 从周二开始并增加 5 天时不起作用(它返回下一个周日)。
      猜你喜欢
      • 1970-01-01
      • 2023-03-08
      • 2013-01-28
      • 1970-01-01
      • 2015-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多