2013-02-13 13 views

Odpowiedz

8

Należy użyć DayOfTheWeek (z jednostki DateUtils) i licznika, iterując od daty początkowej do daty końcowej. (Będziesz także prawdopodobnie trzeba tabelę świąt, aby wykluczyć tych, z liczbą też.)

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; 

można poprawić ten mały, nie martwiąc się o kolejności parametrów (innymi słowy, nie robi „t znaczenia, jeśli start jest przed koniec lub koniec jest przed rozpoczęciem, funkcja będzie nadal działać):

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

Widzę, dziękuję ... Nie potrzebuję wakacji, ponieważ nie wpłynie to znacząco na czas realizacji, ale weekendy są problematyczne. Dam mu szansę. – Sardukar

+0

Użyłem prawie tej samej funkcji. Świetnie. są też okazy, więc jeśli mało kto ma problemy z wakacjami, to nie wpłynie to na całość ... dziękuję. – Sardukar

+7

Byłoby miło zrobić to bez pętli. –

12

Bez pętli wszystkie dni i parametry wejściowe nie w zależności od zamówienia.

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. Miły! Nie miałem okazji przyjrzeć się nie zapętlonemu rozwiązaniu - teraz zdecydowanie nie muszę tego robić. :-) –

+4

Otrzymuję różne wyniki od pozostałych dwóch, z twoją funkcją, jeśli przetestuję 'dt1: = Now' i' dt2: = IncYear (Now, 3) '. – kobik

+5

@kobik, dzięki. Poprawną funkcją numerowania dni jest oczywiście "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; 

Rutynowe BusinessDaysSinceFixedDate oblicza liczbę dni roboczych od ustalonej daty. Konkretna data, która jest nieistotna, to poniedziałek, 25 grudnia, 1899. Po prostu liczy liczbę tygodni, które minęły (X div 7) i mnoży ją przez 5. Następnie dodaje przesunięcie do poprawienia w oparciu o dzień tygodnia. Zauważ, że (X mod 7) zwróci wartość ujemną dla negatywnej terminie, to znaczy przed datą 30 grudnia 1899.

Rutynowe BusinessDaysBetweenDates prostu wywołuje BusinessDaysSinceFixedDate do daty rozpoczęcia i zakończenia oraz odejmuje jeden od drugiego.

+4

+1. Możesz dodać 'Abs' do wyniku' BusinessDaysBetweenDates' (więc wynik Dni będzie zawsze dodatni). – kobik

Powiązane problemy