【问题标题】:Calculate working days between two dates in Javascript excepts holidays计算Javascript中两个日期之间的工作日,节假日除外
【发布时间】:2016-05-06 09:44:15
【问题描述】:

我有一个 javascript 函数,它计算两个日期之间的工作日,它可以工作,但问题是它不考虑假期。如何修改此函数,例如在异常数组中添加假期?

在网上搜索了这个问题,但没有找到关于假期异常的信息。

例如假期数组:

var holidays = ['2016-05-03','2016-05-05'];

我有一个函数来计算这个:

function workingDaysBetweenDates(d0, d1) {
    var startDate = parseDate(d0);
    var endDate = parseDate(d1);  
    // Validate input
    if (endDate < startDate)
        return 0;

    // Calculate days between dates
    var millisecondsPerDay = 86400 * 1000; // Day in milliseconds
    startDate.setHours(0,0,0,1);  // Start just after midnight
    endDate.setHours(23,59,59,999);  // End just before midnight
    var diff = endDate - startDate;  // Milliseconds between datetime objects    
    var days = Math.ceil(diff / millisecondsPerDay);

    // Subtract two weekend days for every week in between
    var weeks = Math.floor(days / 7);
    days = days - (weeks * 2);

    // Handle special cases
    var startDay = startDate.getDay();
    var endDay = endDate.getDay();

    // Remove weekend not previously removed.   
    if (startDay - endDay > 1)         
        days = days - 2;      

    // Remove start day if span starts on Sunday but ends before Saturday
    if (startDay == 0 && endDay != 6)
        days = days - 1  

    // Remove end day if span ends on Saturday but starts after Sunday
    if (endDay == 6 && startDay != 0)
        days = days - 1  

    return days;
}
function parseDate(input) {
    // Transform date from text to date
  var parts = input.match(/(\d+)/g);
  // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based
}

在jsfiddle中做了一个例子:

JSFiddle example

也许还有一些其他功能可以在 Jquery 中轻松使用?

【问题讨论】:

  • 发帖前请先搜索。这已被反复询问和回答。
  • “我有一个函数来计算这个。” 如果它们与问题相关,请将它们放在问题中(不仅仅是链接)。如果没有,可能不值得一提。
  • @Kosmo ,您在哪里看到有节假日例外情况?
  • @Kosmo,它不是重复的,因为它正在寻找随机假期,而不仅仅是周日或周六。 AlexIL,请检查我的答案。
  • 对不起,我理解错了。我删除了我的评论

标签: javascript jquery


【解决方案1】:

试试:

var startDate = new Date('05/03/2016');
var endDate = new Date('05/10/2016');
var numOfDates = getBusinessDatesCount(startDate,endDate);

function getBusinessDatesCount(startDate, endDate) {
    let count = 0;
    const curDate = new Date(startDate.getTime());
    while (curDate <= endDate) {
        const dayOfWeek = curDate.getDay();
        if(dayOfWeek !== 0 && dayOfWeek !== 6) count++;
        curDate.setDate(curDate.getDate() + 1);
    }
    alert(count);
    return count;
}

【讨论】:

  • 但是我怎样才能整合假期数呢?
  • 我知道@dhara-parmar 的答案并没有完全回答原始问题(因为它不考虑假期),但作为计算工作日的快速简便实用程序,这正是我需要。
  • 这对我有用,但 startDate 在函数中被修改。我通过执行以下操作解决了这个问题:var curDate = new Date(startDate.getTime());
【解决方案2】:

实现它的最简单方法是查找开始日期和结束日期之间的这几天。

编辑:我添加了额外的验证,以确保仅减去 holidays 数组中的工作日。

$(document).ready(() => {
  $('#calc').click(() => {
  var d1 = $('#d1').val();
  var d2 = $('#d2').val();
    $('#dif').text(workingDaysBetweenDates(d1,d2));
  });
});

let workingDaysBetweenDates = (d0, d1) => {
  /* Two working days and an sunday (not working day) */
  var holidays = ['2016-05-03', '2016-05-05', '2016-05-07'];
  var startDate = parseDate(d0);
  var endDate = parseDate(d1);  

// Validate input
  if (endDate <= startDate) {
    return 0;
  }

// Calculate days between dates
  var millisecondsPerDay = 86400 * 1000; // Day in milliseconds
  startDate.setHours(0, 0, 0, 1);  // Start just after midnight
  endDate.setHours(23, 59, 59, 999);  // End just before midnight
  var diff = endDate - startDate;  // Milliseconds between datetime objects    
  var days = Math.ceil(diff / millisecondsPerDay);

  // Subtract two weekend days for every week in between
  var weeks = Math.floor(days / 7);
  days -= weeks * 2;

  // Handle special cases
  var startDay = startDate.getDay();
  var endDay = endDate.getDay();
    
  // Remove weekend not previously removed.   
  if (startDay - endDay > 1) {
    days -= 2;
  }
  // Remove start day if span starts on Sunday but ends before Saturday
  if (startDay == 0 && endDay != 6) {
    days--;  
  }
  // Remove end day if span ends on Saturday but starts after Sunday
  if (endDay == 6 && startDay != 0) {
    days--;
  }
  /* Here is the code */
  holidays.forEach(day => {
    if ((day >= d0) && (day <= d1)) {
      /* If it is not saturday (6) or sunday (0), substract it */
      if ((parseDate(day).getDay() % 6) != 0) {
        days--;
      }
    }
  });
  return days;
}
           
function parseDate(input) {
    // Transform date from text to date
  var parts = input.match(/(\d+)/g);
  // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])
  return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="d1" value="2016-05-02"><br>
<input type="text" id="d2" value="2016-05-08">

<p>Working days count: <span id="dif"></span></p>
<button id="calc">Calc</button>

<p>
Now it shows 5 days, but I need for example add holidays 
3 and 5 May (2016-05-03 and 2016-05-05) so the result will be 3 working days
</p>

【讨论】:

  • 对不起,我尝试重用函数参数但我不能,所以我用$('#d1').val()代替parseDate(d0)
  • 谢谢!我已对您的回答进行了更改。现在一切正常:)
  • 不客气,我也使用days-- 改进了它,而不是days = days - 1。我不知道为什么当我进行相同的更改时,代码显示“5 天”:) 编辑:啊! parseDate 返回一个日期,而不是一个字符串! :D
  • 这是完美的,除了当两个日期相同时它给我 1 而不是 0 所以我从末尾减去一个
  • 一天,同样的两天问题不用减去,直接加:if (endDate &lt;= startDate) { return 0; } --> if (endDate &lt; startDate) { return 0; } else if (endDate == startDate) { return 1; } 这个不会检查节假日和周末谁想加一天还是在上面?
【解决方案3】:

我认为这个解决方案要简单得多

const numberOfDaysInclusive = (d0, d1) => {
  return 1 + Math.round((d1.getTime()-d0.getTime())/(24*3600*1000));
}

const numberOfWeekends = (d0, d1) => {
    const days = numberOfDaysInclusive(d0, d1); // total number of days
    const sundays = Math.floor((days + (d0.getDay() + 6) % 7) / 7); // number of sundays
    return 2*sundays + (d1.getDay()==6) - (d0.getDay()==0); // multiply sundays by 2 to get both sat and sun, +1 if d1 is saturday, -1 if d0 is sunday
}

const numberOfWeekdays = (d0, d1) => {
    return numberOfDaysInclusive(d0, d1) - numberOfWeekends(d0, d1);
}

【讨论】:

  • 您的计算似乎忽略了假期。
【解决方案4】:

获取两个日期之间的所有工作日:

private getCorrectWeekDays(StartDate,EndDate){
 let _weekdays = [0,1,2,3,4];
 var wdArr= [];
 var currentDate = StartDate;
 while (currentDate <= EndDate) {
  if ( _weekdays.includes(currentDate.getDay())){
    wdArr.push(currentDate);
    //if you want to format it to yyyy-mm-dd
    //wdArr.push(currentDate.toISOString().split('T')[0]);
  }
  currentDate.setDate(currentDate.getDate() +1);
}

 return wdArr;
}

【讨论】:

    【解决方案5】:

    我对@OscarGarcia 采取了类似的方法,主要是作为练习,因为我的 JS 生锈了。

    虽然看起来很相似,但如果假期恰好在周六或周日,请注意不要将一天减去两次。这样,您可以预先加载重复日期列表(例如 12 月 25 日、1 月 1 日、7 月 4 日,这些日期可能是也可能不是在其他工作日 - 周一到周五 -)

    $(document).ready(function(){
        $('#calc').click(function(){
      var d1 = $('#d1').val();
      var d2 = $('#d2').val();
            $('#dif').text(workingDaysBetweenDates(d1,d2));
        });
    });
    function workingDaysBetweenDates(d0, d1) {
        var startDate = parseDate(d0);
        var endDate = parseDate(d1);
        // populate the holidays array with all required dates without first taking care of what day of the week they happen
        var holidays = ['2018-12-09', '2018-12-10', '2018-12-24', '2018-12-31'];
        // Validate input
        if (endDate < startDate)
            return 0;
    
        var z = 0; // number of days to substract at the very end
        for (i = 0; i < holidays.length; i++)
        {
            var cand = parseDate(holidays[i]);
            var candDay = cand.getDay();
    
          if (cand >= startDate && cand <= endDate && candDay != 0 && candDay != 6)
          {
            // we'll only substract the date if it is between the start or end dates AND it isn't already a saturday or sunday
            z++;
          }
    
        }
        // Calculate days between dates
        var millisecondsPerDay = 86400 * 1000; // Day in milliseconds
        startDate.setHours(0,0,0,1);  // Start just after midnight
        endDate.setHours(23,59,59,999);  // End just before midnight
        var diff = endDate - startDate;  // Milliseconds between datetime objects    
        var days = Math.ceil(diff / millisecondsPerDay);
    
        // Subtract two weekend days for every week in between
        var weeks = Math.floor(days / 7);
        days = days - (weeks * 2);
    
        // Handle special cases
        var startDay = startDate.getDay();
        var endDay = endDate.getDay();
    
        // Remove weekend not previously removed.   
        if (startDay - endDay > 1)         
            days = days - 2;      
    
        // Remove start day if span starts on Sunday but ends before Saturday
        if (startDay == 0 && endDay != 6)
            days = days - 1  
    
        // Remove end day if span ends on Saturday but starts after Sunday
        if (endDay == 6 && startDay != 0)
            days = days - 1  
    
        // substract the holiday dates from the original calculation and return to the DOM
        return days - z;
    }
    function parseDate(input) {
        // Transform date from text to date
      var parts = input.match(/(\d+)/g);
      // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])
      return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based
    }
    

    2018-12-09 是星期天...使用此代码,它只会被减去一次(因为是星期天)而不是两次(如果我们只检查它是否是国定假日)

    【讨论】:

    • 感谢您的改进 (+1)。我使用(parseDate(holidays[i]).getDay() % 6) != 0 实现它,仅在必要时检查它(选定日期之间的一天)。
    【解决方案6】:

    你也可以试试这段代码:

    const moment = require('moment-business-days');
    /**
     *
     * @param {String} date - iso Date
     * @returns {Number} difference between now and @param date
     */
    const calculateDaysLeft = date => {
      try {
         return moment(date).businessDiff(moment(new Date()))
      } catch (err) {
         throw new Error(err)
      }
    }
    

    【讨论】:

    • 这对我来说似乎是最好的解决方案,因为它允许为语言环境配置假期。
    【解决方案7】:

    最佳答案确实有效,但有一个缺陷。
    当圣日在星期六或星期日时,它仍然会减少一天。

    将此添加到现有代码中:

    .... /* Here is the code */
    for (var i in holidays) {
      if ((holidays[i] >= d0) && (holidays[i] <= d1)) {
    
        // Check if specific holyday is Saturday or Sunday
          var yourDate = new Date(holidays[i]);
          if(yourDate.getDay() === 6 || yourDate.getDay() === 0){
    
              // If it is.. do nothing
    
          } else {
    
              // if it is not, reduce a day..
              days--;
          }
      }
    }
    

    【讨论】:

    • 感谢您的评论和代码 (+1)。我通过(parseDate(holidays[i]).getDay() % 6) != 0 实现它,仅在必要时检查它(选定日期之间的一天)。
    • 当然,您也可以这样做。因为不熟悉php语法的人,我这样写代码很容易理解
    • 这不是 php 语法或代码,它是 javascript。 Remainder operator (%)Date.getDay() method 都是 javascript。
    • 我的错误 xD 当我评论它时我正在使用 php。没注意到我写的是 php 而不是 javascript xD
    【解决方案8】:

    简单地从你得到的值中减少数组的长度(在你的小提琴中)

    var numberofdayswithoutHolidays= 5;
    var holidays = ['2016-05-03','2016-05-05'];
    alert( numberofdayswithoutHolidays - holidays.length );
    

    您还需要从假期中过滤掉周末

    holidays = holidays.filter( function(day){
      var day = parseDate( day ).getDay();
      return day > 0 && day < 6;
    })
    

    【讨论】:

    • 逻辑不正确。例如,我将有一个带假期的数组:var holidays = ['2016-05-03','2016-05-05','2016-12-31']; 并且对于所有时段,它都将计入 -3
    • @AlexIL true,如果您的假期也包括周末。但是你可以运行另一个循环来过滤掉这个 holidays 数组中的周末
    • @AlexIL 在从计数中减去之前检查逻辑以过滤掉假期(你已经有)。
    【解决方案9】:

    $(document).ready(() => {
      $('#calc').click(() => {
      var d1 = $('#d1').val();
      var d2 = $('#d2').val();
        $('#dif').text(workingDaysBetweenDates(d1,d2));
      });
    });
    
    let workingDaysBetweenDates = (d0, d1) => {
      /* Two working days and an sunday (not working day) */
      var holidays = ['2016-05-03', '2016-05-05', '2016-05-07'];
      var startDate = parseDate(d0);
      var endDate = parseDate(d1);  
    
    // Validate input
      if (endDate < startDate) {
        return 0;
      }
    
    // Calculate days between dates
      var millisecondsPerDay = 86400 * 1000; // Day in milliseconds
      startDate.setHours(0, 0, 0, 1);  // Start just after midnight
      endDate.setHours(23, 59, 59, 999);  // End just before midnight
      var diff = endDate - startDate;  // Milliseconds between datetime objects    
      var days = Math.ceil(diff / millisecondsPerDay);
    
      // Subtract two weekend days for every week in between
      var weeks = Math.floor(days / 7);
      days -= weeks * 2;
    
      // Handle special cases
      var startDay = startDate.getDay();
      var endDay = endDate.getDay();
        
      // Remove weekend not previously removed.   
      if (startDay - endDay > 1) {
        days -= 2;
      }
      // Remove start day if span starts on Sunday but ends before Saturday
      if (startDay == 0 && endDay != 6) {
        days--;  
      }
      // Remove end day if span ends on Saturday but starts after Sunday
      if (endDay == 6 && startDay != 0) {
        days--;
      }
      /* Here is the code */
      holidays.forEach(day => {
        if ((day >= d0) && (day <= d1)) {
          /* If it is not saturday (6) or sunday (0), substract it */
          if ((parseDate(day).getDay() % 6) != 0) {
            days--;
          }
        }
      });
      return days;
    }
               
    function parseDate(input) {
    	// Transform date from text to date
      var parts = input.match(/(\d+)/g);
      // new Date(year, month [, date [, hours[, minutes[, seconds[, ms]]]]])
      return new Date(parts[0], parts[1]-1, parts[2]); // months are 0-based
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <input type="text" id="d1" value="2016-05-02"><br>
    <input type="text" id="d2" value="2016-05-08">
    
    <p>Working days count: <span id="dif"></span></p>
    <button id="calc">Calc</button>
    
    <p>
    Now it shows 5 days, but I need for example add holidays 
    3 and 5 May (2016-05-03 and 2016-05-05) so the result will be 3 working days
    </p>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-20
      • 1970-01-01
      • 2015-07-27
      • 2018-08-03
      • 2014-10-20
      • 1970-01-01
      相关资源
      最近更新 更多