2013-02-13 7 views
11

Мне нужно вычислить количество рабочих дней (рабочих дней) между двумя заданными датами. Рабочие дни - это дни недели, кроме субботы и воскресенья. Я не рассматриваю праздники в этом счете.Как рассчитать количество рабочих дней между двумя датами?

Как рассчитать количество рабочих дней между двумя датами?

ответ

8

Вам необходимо использовать DayOfTheWeek (от блока DateUtils) и счетчик, итерационный период начиная с даты начала и окончания. (Вы также, вероятно, понадобится таблица праздников, чтобы исключить те из вашего графа также.)

function BusinessDaysBetween(const StartDate, EndDate: TDateTime): Integer; 
var 
    CurrDate : TDateTime; 
begin 
    CurrDate := StartDate; 
    Result := 0; 
    while (CurrDate <= EndDate) do 
    begin 
    // DayOfTheWeek returns 1-5 for Mon-Fri, so 6 and 7 are weekends 
    if DayOfTheWeek(CurrDate) < 6 then 
     Inc(Result); 
    CurrDate := CurrDate + 1; 
    end; 
end; 

Вы можете улучшить это немного, не заботясь о порядке параметров (другими словами, это Безразлично «т имеет значение, если старт до конца или конец перед стартом, то функция будет продолжать работать):

function BusinessDaysBetween(const FirstDate, SecondDate: TDateTime): Integer; 
var 
    CurrDate : TDateTime; 
    StartDate, EndDate: TDateTime; 
begin 
    if SecondDate > FirstDate then 
    begin 
    StartDate := FirstDate; 
    EndDate := SecondDate; 
    end 
    else 
    begin 
    StartDate := SecondDate; 
    EndDate := FirstDate; 
    end; 

    CurrDate := StartDate; 
    Result := 0; 

    while (CurrDate <= EndDate) do 
    begin 
    if DayOfTheWeek(CurrDate) < 6 then 
     Inc(Result); 
    CurrDate := CurrDate + 1; 
    end; 
end; 
+0

Я вижу, спасибо ... Мне не нужны праздники, так как они не будут сильно влиять на время поворота ... но выходные - проблема. Я сделаю это. – Sardukar

+0

Я использовал почти ту же функцию. Отлично работает. есть также и образцы, поэтому, если у некоторых из них есть проблемы с праздниками, они не повлияют на общее. – Sardukar

+7

Было бы неплохо сделать это без цикла. –

12

Без зацикливания всех дней и входные параметры, не зависящие от порядка.

Uses DateUtils,Math; 

function WorkingDaysBetween(const firstDate,secondDate : TDateTime) : Integer; 
var 
    startDate,stopDate : TDateTime; 
    startDow,stopDow : Integer; 
begin 
    if (firstDate < secondDate) then 
    begin 
    startDate := firstDate; 
    stopDate := secondDate; 
    end 
    else 
    begin 
    startDate := secondDate; 
    stopDate := firstDate; 
    end; 
    startDow := DayOfTheWeek(startDate); 
    stopDow := DayOfTheWeek(stopDate); 
    if (stopDow >= startDow) then 
    stopDow := Min(stopDow,6) 
    else 
    Inc(stopDow,5); 

    Result := 
    5*WeeksBetween(stopDate,startDate) + 
    (stopDow - Min(startDow,6)); 
end; 
+3

+1. Ницца! У меня не было возможности взглянуть на не-петлевое решение - теперь мне определенно не нужно это делать. :-) –

+4

Я получаю разные результаты от двух других, с вашей функцией, если я тестирую 'dt1: = Now' и' dt2: = IncYear (Now, 3) '. – kobik

+5

@kobik, спасибо. Правильная функция нумерации дня - это, конечно, 'DayOfTheWeek()'. –

13
function BusinessDaysSinceFixedDate (const nDate : tDateTime) : integer; 
const 
    Map : array [ -6 .. 6 ] of integer 
     = ( 0, 0, 1, 2, 3, 4, 5, 5, 5, 6, 7, 8, 9); 
var 
    X : integer; 
begin 
    X := trunc (nDate); 
    Result := 5 * (X div 7) + Map [ X mod 7 ]; 
end; 

function BusinessDaysBetweenDates (const nStartDate : tDateTime; 
            const nEndDate : tDateTime) : integer; 
begin 
    Result := BusinessDaysSinceFixedDate (nEndDate) 
      - BusinessDaysSinceFixedDate (nStartDate); 
end; 

Процедура BusinessDaysSinceFixedDate вычисляет количество рабочих дней с фиксированной датой. Конкретная дата, которая не имеет значения, - понедельник, 25 декабря, 1899. Он просто подсчитывает количество прошедших недель (X div 7) и умножает их на 5. Затем он добавляет смещение, чтобы исправить в зависимости от дня недели. Заметим, что (Х мод 7) будет возвращать отрицательное значение для отрицательного дату, т.е. дату до 30 декабря, 1899.

В рутинные BusinessDaysBetweenDates просто вызывает BusinessDaysSinceFixedDate для начальной и конечной даты и вычитает одно от другого.

+4

+1. Вы можете добавить 'Abs' к результату' BusinessDaysBetweenDates' (так что результат Days будет всегда положительным). – kobik

Смежные вопросы