在Javascript中计算两个日期之间的工作日,节假日除外

Calculate working days between two dates in Javascript excepts holidays

本文关键字:工作日 之间 节假日 日期 两个 计算 Javascript      更新时间:2023-09-26

我有一个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示例

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

尝试:

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;
}

实现这一目标的最简单方法是在开始和结束日期之间寻找这几天。

编辑:我添加了一个额外的验证,以确保只减去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>

我对@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是一个星期天。。。有了这个代码,它只会被减去一次(因为是星期天),而不会被减去两次(如果我们只检查它是否是国家假日的话)

我认为这个解决方案更简单

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);
}

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

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;
}

您也可以尝试以下代码:

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)
  }
}

最重要的答案实际上有效,但有一个缺陷
当假日在周六或周日时,它仍然会减少一天

将其添加到现有代码中:

.... /* 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--;
      }
  }
}
const workday_count = (start, end) => {
start = moment(start).format(("YYYY-MM-DD"))
end = moment(end).format(("YYYY-MM-DD"))
let workday_count = 0;
let totalDays = moment(end).diff(moment(start), "days");
let date = start
for (let i = 1; i <= totalDays; i++) {
    if (i == 1) {
        date = moment(date)
    } else {
        date = moment(date).add(1, "d");
    }
    date = new Date(date);
    let dayOfWeek = date.getDay();
    let isWeekend = (dayOfWeek === 6) || (dayOfWeek === 0);
    if (!isWeekend) {
        workday_count = workday_count + 1;
    }
}
return workday_count;

}

只需从的值中减少数组的长度

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;
})

$(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>