Как рассчитать число "рабочих дней" между двумя датами в Javascript, используя moment.js?

Как рассчитать количество рабочих дней между двумя датами в JavaScript с помощью moment.js. У меня есть рабочая формула, которая вычисляет эти дни, но формула не удовлетворяет всем условиям:

вот мой код:

var start= moment(data[x].start_date);
                var end= moment(data[x].est_end_date);
                var difference= end.diff(start, 'days');
                var workingDays= Math.round((difference/7)*5);
//data[x] is for iterating over a loop

Я получаю пять дней в течение 7 дней здесь, потому что суббота и воскресенье рассматриваются как нерабочие дни, но эта формула терпит неудачу, если подсчет дней начнется с воскресенья или субботы.

Пожалуйста, любой может помочь в этом отношении, что необходимо внести необходимые изменения, чтобы избежать этой проблемы.

Ответ 1

Просто разделите его на 3 части. Первая неделя, последняя неделя и промежуточный, что-то вроде этого:

function workday_count(start,end) {
  var first = start.clone().endOf('week'); // end of first week
  var last = end.clone().startOf('week'); // start of last week
  var days = last.diff(first,'days') * 5 / 7; // this will always multiply of 7
  var wfirst = first.day() - start.day(); // check first week
  if(start.day() == 0) --wfirst; // -1 if start with sunday 
  var wlast = end.day() - last.day(); // check last week
  if(end.day() == 6) --wlast; // -1 if end with saturday
  return wfirst + days + wlast; // get the total
}

Код проверки

var ftest = {date:'2015-02-0',start:1,end:7};
var ltest = {date:'2015-02-2',start:2,end:8};
var f = 'YYYY-MM-DD';
for(var z=ftest.start; z<=ftest.end; ++z) {
  var start = moment(ftest.date + z);
  for(var y=ltest.start; y<=ltest.end; ++y) {
    var end = moment(ltest.date + y);
    var wd = workday_count(start,end);
    console.log('from: '+start.format(f),'to: '+end.format(f),'is '+wd+' workday(s)');
  }
}

Выход тестового кода:

from: 2015-02-01 to: 2015-02-22 is 15 workday(s)
from: 2015-02-01 to: 2015-02-23 is 16 workday(s)
from: 2015-02-01 to: 2015-02-24 is 17 workday(s)
from: 2015-02-01 to: 2015-02-25 is 18 workday(s)
from: 2015-02-01 to: 2015-02-26 is 19 workday(s)
from: 2015-02-01 to: 2015-02-27 is 20 workday(s)
from: 2015-02-01 to: 2015-02-28 is 20 workday(s)
from: 2015-02-02 to: 2015-02-22 is 15 workday(s)
from: 2015-02-02 to: 2015-02-23 is 16 workday(s)
from: 2015-02-02 to: 2015-02-24 is 17 workday(s)
from: 2015-02-02 to: 2015-02-25 is 18 workday(s)
from: 2015-02-02 to: 2015-02-26 is 19 workday(s)
from: 2015-02-02 to: 2015-02-27 is 20 workday(s)
from: 2015-02-02 to: 2015-02-28 is 20 workday(s)
from: 2015-02-03 to: 2015-02-22 is 14 workday(s)
from: 2015-02-03 to: 2015-02-23 is 15 workday(s)
from: 2015-02-03 to: 2015-02-24 is 16 workday(s)
from: 2015-02-03 to: 2015-02-25 is 17 workday(s)
from: 2015-02-03 to: 2015-02-26 is 18 workday(s)
from: 2015-02-03 to: 2015-02-27 is 19 workday(s)
from: 2015-02-03 to: 2015-02-28 is 19 workday(s)
from: 2015-02-04 to: 2015-02-22 is 13 workday(s)
from: 2015-02-04 to: 2015-02-23 is 14 workday(s)
from: 2015-02-04 to: 2015-02-24 is 15 workday(s)
from: 2015-02-04 to: 2015-02-25 is 16 workday(s)
from: 2015-02-04 to: 2015-02-26 is 17 workday(s)
from: 2015-02-04 to: 2015-02-27 is 18 workday(s)
from: 2015-02-04 to: 2015-02-28 is 18 workday(s)
from: 2015-02-05 to: 2015-02-22 is 12 workday(s)
from: 2015-02-05 to: 2015-02-23 is 13 workday(s)
from: 2015-02-05 to: 2015-02-24 is 14 workday(s)
from: 2015-02-05 to: 2015-02-25 is 15 workday(s)
from: 2015-02-05 to: 2015-02-26 is 16 workday(s)
from: 2015-02-05 to: 2015-02-27 is 17 workday(s)
from: 2015-02-05 to: 2015-02-28 is 17 workday(s)
from: 2015-02-06 to: 2015-02-22 is 11 workday(s)
from: 2015-02-06 to: 2015-02-23 is 12 workday(s)
from: 2015-02-06 to: 2015-02-24 is 13 workday(s)
from: 2015-02-06 to: 2015-02-25 is 14 workday(s)
from: 2015-02-06 to: 2015-02-26 is 15 workday(s)
from: 2015-02-06 to: 2015-02-27 is 16 workday(s)
from: 2015-02-06 to: 2015-02-28 is 16 workday(s)
from: 2015-02-07 to: 2015-02-22 is 10 workday(s)
from: 2015-02-07 to: 2015-02-23 is 11 workday(s)
from: 2015-02-07 to: 2015-02-24 is 12 workday(s)
from: 2015-02-07 to: 2015-02-25 is 13 workday(s)
from: 2015-02-07 to: 2015-02-26 is 14 workday(s)
from: 2015-02-07 to: 2015-02-27 is 15 workday(s)
from: 2015-02-07 to: 2015-02-28 is 15 workday(s)

Ответ 2

Я использую простую функцию для достижения этой цели. Может быть, не самый эффективный, но это работает. Это не требует Moment.js. это просто Javascript.

function getNumWorkDays(startDate, endDate) {
    var numWorkDays = 0;
    var currentDate = new Date(startDate);
    while (currentDate <= endDate) {
        // Skips Sunday and Saturday
        if (currentDate.getDay() !== 0 && currentDate.getDay() !== 6) {
            numWorkDays++;
        }
        currentDate = currentDate.addDays(1);
    }
    return numWorkDays;
}

Для addDays я использую следующую функцию:

Date.prototype.addDays = function (days) {
    var date = new Date(this.valueOf());
    date.setDate(date.getDate() + days);
    return date;
};

Ответ 3

Я обнаружил, что ответ kokizzu не работал, если дни были на той же неделе (например, солнце, чтобы сидеть), поэтому решили для этого:

    function calcBusinessDays(startDate, endDate) { 
      var day = moment(startDate);
      var businessDays = 0;

      while (day.isSameOrBefore(endDate,'day')) {
        if (day.day()!=0 && day.day()!=6) businessDays++;
        day.add(1,'d');
      }
      return businessDays;
    }

Ответ 4

Я сделал адаптацию к ответу Кокиццу, чтобы решить проблему летнего времени. В бразильском часовом поясе (GMT -3) разница между 17/10/2017 и 18/10/2017 составляла -2.71 вместо 2.

Начало недели было 15.10.2017 00:00 UTC или 14.10.2017 21: 00-03: 00

Конец недели был 22/10/2017 00:00 UTC или 21/10/2017 22: 00-02: 00 (летнее время)

Поэтому вместо 7 разница между "первой" и "последней" переменной в днях составляла 6 (или 8, в зависимости от вашего часового пояса).

Код исправлен ниже:

start = moment(start).utc().add(start.utcOffset(), 'm'); // Ignore timezones
end = moment(end).utc().add(end.utcOffset(), 'm'); // Ignore timezones

var first = start.clone().endOf('week'); // end of first week
var last = end.clone().startOf('week'); // start of last week

// Fixing Summer Time problems
firstCorrection = moment(first).utc().add(60, 'm').toDate(); //
var days = last.diff(firstCorrection,'days') * 5 / 7; // this will always multiply of 7

var wfirst = first.day() - start.day(); // check first week
if(start.day() == 0) --wfirst; // -1 if start with sunday
var wlast = end.day() - last.day(); // check last week
if(end.day() == 6) --wlast; // -1 if end with saturday
return wfirst + days + wlast; // get the total (subtract holidays if needed)

Ответ 5

Используя momentjs, это возможно следующим образом:

private calculateWorkdays(startDate: Date, endDate: Date): number {
// + 1 cause diff returns the difference between two moments, in this case the day itself should be included.

const totalDays: number = moment(endDate).diff(moment(startDate), 'days') + 1;
const dayOfWeek = moment(startDate).isoWeekday();
let totalWorkdays = 0;

for (let i = dayOfWeek; i < totalDays + dayOfWeek; i++) {
    if (i % 7 !== 6 && i % 7 !== 0) {
      totalWorkdays++;
    }
  }
  return totalWorkdays;
}

Ответ 6

Вы можете попробовать это (без цикла):

  function getBusinessDays(endDate, startDate) {
    var lastDay = moment(endDate);
    var firstDay = moment(startDate);
    let calcBusinessDays = 1 + (lastDay.diff(firstDay, 'days') * 5 -
      (firstDay.day() - lastDay.day()) * 2) / 7;

    if (lastDay.day() == 6) calcBusinessDays--;//SAT
    if (firstDay.day() == 0) calcBusinessDays--;//SUN

    return calcBusinessDays;
  }

Исходный код