Хобрук: Ваш путь к мастерству в программировании

Как рассчитать количество рабочих дней между двумя датами в 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 + Math.floor(days) + wlast; // get the total
} //              ^ EDIT: if days count less than 7 so no decimal point

Тестовый код

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)
10.02.2015
  • Для диапазона дат 5 дней получается 5,7 дня. 21.09.2017
  • Фактически, для диапазона дат менее 7 дней значение указывается в десятичных числах. 21.09.2017
  • У меня такая же проблема. Это произошло из-за разницы в летнем времени между началом и концом недели. Исправление ниже. 17.10.2017
  • Просто добавьте Math.floor(days), это решит проблему '__') спасибо, что заметили это, ребята 05.03.2020

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

    3

    Я адаптировал ответ Kokizzu, чтобы решить проблему с летним временем. В бразильском часовом поясе (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)
    
    17.10.2017

    4

    Я обнаружил, что ответ 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;
        }
    
    03.08.2017
  • отлично работает в течение нескольких месяцев для меня ... возможно, вы можете поделиться своим кодом / ошибкой? 10.12.2019

  • 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;
    }
    
    14.08.2019
  • Добро пожаловать в SO! Ответы на stackoverflow.com разрешены только на английском языке. Для получения дополнительной информации прочитайте этот пост 14.08.2019

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

    Исходный источник

    14.01.2019

    7

    Я использовал полезную библиотеку момент-рабочие-дни в сочетании с моментом

    Ссылка NPM на момент-рабочие дни

    NPM Link of Moment

    Пример того, сколько рабочих дней между

    const diff = moment('05-15-2017', 'MM-DD-YYYY').businessDiff(moment('05-08-2017','MM-DD-YYYY'));
    // diff = 5
    
    06.08.2020
    Новые материалы

    Понимание СТРУКТУРЫ ДАННЫХ И АЛГОРИТМА.
    Что такое структуры данных и алгоритмы? Термин «структура данных» используется для описания того, как данные хранятся, а алгоритм используется для описания того, как данные сжимаются. И данные, и..

    Как интегрировать модель машинного обучения на ios с помощью CoreMl
    С выпуском новых функций, таких как CoreML, которые упростили преобразование модели машинного обучения в модель coreML. Доступная модель машинного обучения, которую можно преобразовать в модель..

    Создание успешной организации по науке о данных
    "Рабочие часы" Создание успешной организации по науке о данных Как создать эффективную группу по анализу данных! Введение Это обзорная статья о том, как создать эффективную группу по..

    Технологии и проблемы будущей работы
    Изучение преимуществ и недостатков технологий в образовании В быстро меняющемся мире технологии являются решающим фактором в формировании будущего работы. Многие отрасли уже были..

    Игорь Минар из Google приедет на #ReactiveConf2017
    Мы рады сообщить еще одну замечательную новость: один из самых востребованных спикеров приезжает в Братиславу на ReactiveConf 2017 ! Возможно, нет двух других кланов разработчиков с более..

    Я собираюсь научить вас Python шаг за шагом
    Привет, уважаемый энтузиаст Python! 👋 Готовы погрузиться в мир Python? Сегодня я приготовил для вас кое-что интересное, что сделает ваше путешествие более приятным, чем шарик мороженого в..

    Альтернатива шаблону исходящих сообщений для архитектуры микросервисов
    Познакомьтесь с двухэтапным сообщением В этой статье предлагается альтернативный шаблон для папки Исходящие : двухэтапное сообщение. Он основан не на очереди сообщений, а на..