2010-09-14 15 views
8

potrzebujesz pomocy. Muszę liczyć regularne dni robocze dla danego okresu, na przykład w naszym kraju, mamy 5 regularnych dni roboczych od poniedziałku do piątku, następnie w kodzie muszę wykluczyć soboty i niedziele, kiedy używam go na moich obliczeniach.Zliczanie regularnych dni roboczych w danym okresie czasu

Potrzebuję czegoś algorytmu takiego w C#.

int GetRegularWorkingDays(DateTime startDate, DateTime endDate) 
    { 

     int nonWorkingDays = ((endDate - startDate) % 7) * 2; 

     return (endDate - startDate) - nonWorkingDays; 
    } 

wiem, że mój projekt jest sposobem daleko :(Z góry dziękuję =)

. PS: Chłopaki proszę up-głosowania najlepsza/najszybsza/najskuteczniejsza odpowiedź poniżej. Thanks =)

+3

Jak chcesz leczyć wakacje? – kbrimington

+0

To również pytanie, ale moje rozwiązanie jest po prostu nadrzędne w moich obliczeniach. Regularne wakacje tutaj w naszym kraju są ciągle zmienne. I nie chcę powiedzieć, budować tabelę kalendarza tylko po to, aby ją utrzymać .. – CSharpNoob

Odpowiedz

18

Wyjazd this example on Code Project że używa bardzo skuteczny sposób, który nie wiąże się z jakąkolwiek zapętlenie;)

Używa tego algorytmu:

  1. Oblicz liczbę przedziałów czasowych w kategoriach tygodni. Zadzwoń, W.
  2. Odejmij pierwszy tydzień od liczby tygodni. W = W-1
  3. Pomnóż liczbę tygodni z liczbą dni roboczych na tydzień . Zadzwoń, D.
  4. Dowiedz się święta w określonym przedziale czasowym. Nazwij to, H.
  5. Oblicz dni w pierwszym tygodniu. Zadzwoń, SD.
  6. Oblicz dni w ostatnim tygodniu. Nazwij to, ED.
  7. Podsumuj wszystkie dni. BD = D + SD + ED H.
+5

To naprawdę klucz. Jeśli masz 6 lub 7 (lub 66 lub 77) przerwy tygodniowe, nie musisz powtarzać tygodnia po tygodniu, pomijając sobotę i niedz. Pierwszy tydzień i ostatni tydzień to przypadki szczególne, nie wiesz, czy rozpiętość obejmuje dni powszednie czy weekendy, ale duży środek to tylko 5-dniowe mniej pracy za urlop. Pozwoli to zaoszczędzić wiele obliczeń. –

+0

+1: Nie jestem pewien, dlaczego wszystkie pętle są przegłosowane, kiedy to rozwiązanie jest zasadniczo O (1) ... Jednak krok 4 nie jest wymagany zgodnie z pytaniem PO. – Dirk

+0

obecnie czytasz. to jest interesujące, nie ma pętli .. – CSharpNoob

2

Możesz wypróbować prostą metodę liczenia dni. Jeśli zwykle robi się to przez okresy czasu, np. Miesiące, a nie lata, i nie jest wywoływana wielokrotnie, nie będzie to hitem wydajnościowym, który wystarczy przejść.

int GetWorkingDays(DateTime startDate, DateTime endDate) 
{ 
    int count = 0; 
    for (DateTime currentDate = startDate; currentDate < endDate; currentDate = currentDate.AddDays(1)) 
    { 
     if (currentDate.DayOfWeek == DayOfWeek.Sunday || currentDate.DayOfWeek == DayOfWeek.Saturday) 
     { 
      continue; 
     } 
     count++; 
    } 
    return count; 
} 
+0

Potrzebuję również śledzić dni wolne od pracy, jeśli zastąpię kontynuację rachunkiem nonworkingday? – CSharpNoob

+1

Najpierw musisz mieć przechowywanie wszystkich świąt (predefiniowane) i sprawdzić, czy bieżące dni pasują do day_holiday_table ... nie powinieneś tego liczyć, a reszta to dni robocze. –

+0

Mam różne rozwiązania leczenia wakacji. a tworzenie tabeli bazy danych właśnie do tego nie jest moją opcją. Po prostu chcę liczyć poniedziałki-piątki .. Dzięki btw =) – CSharpNoob

2

Niezbyt szybko, ale będzie to rade:

int GetRegularWorkingDays(DateTime start, DateTime end) 
{ 
    return (
     from day in Range(start, end) 
     where day.DayOfWeek != DayOfWeek.Saturday 
     where day.DayOfWeek != DayOfWeek.Sunday 
     select day).Count(); 
} 

IEnumerable<DateTime> Range(DateTime start, DateTime end) 
{ 
    while (start <= end) 
    { 
     yield return start; 
     start = start.AddDays(1); 
    } 
} 
+0

Dziękuję, proszę pana, ale potrzebuję też najbardziej wydajnego, ponieważ będę go używał w pętli For For Loop ze średnią 5000 wierszy .. dzięki .. – CSharpNoob

4

One-liner!

int workingDays = Enumerable.Range(0, Convert.ToInt32(endDate.Subtract(startDate).TotalDays)).Select(i=>new [] { DayOfWeek.Saturday, DayOfWeek.Sunday }.Contains(startDate.AddDays(i).DayOfWeek) ? 0 : 1).Sum(); 

Albo bardziej efektywne:

DayOfWeek currDay = startDate.DayOfWeek; 
int nonWorkingDays = 0; 

foreach(var i in Enumerable.Range(0, Convert.ToInt32(endDate.Subtract(startDate).TotalDays))) 
{ 
    if(currDay == DayOfWeek.Sunday || currDay == DayOfWeek.Saturday) 
      nonWorkingDays++; 
    if((int)++currDay > 6) currDay = (DayOfWeek)0; 
} 
+3

Ja don nie nazywają tego jednym linerem. Nazywam to bardzo długą linią :-) – Steven

+0

człowiek ten niesamowity, ale co z jego skutecznością? dziękuję, mam na myśli wydajność hit – CSharpNoob

+0

Mwah, jeśli nie robisz oprogramowania bankowego to naprawdę nie obchodzi, ale budujesz tablicę i obiekt datetime. Sprawdź moją edycję dla supa dupa w skuteczny sposób. –

0

Prosta metoda, aby uzyskać dni praca:

int GetRegularWorkingDays(DateTime startDate, DateTime endDate) 
{ 
    int total = 0; 

    if (startDate < endDate) 
    { 
     var days = endDate - startDate; 

     for(; startDate < endDate; startDate = startDate.AddDays(1)) 
     { 
      switch(startDate.DayOfWeek) 
      { 
       case DayOfWeek.Saturday : 
       case DayOfWeek.Sunday :      
        break; 
       default: 
        total++; 
        break; 
      } 
     } 
    } 
    return total; 
} 
1

Można to zrobić z czasem linia klasy pomocnika - klasa ta pozwala również na innych przedziałach:

public class TimeLine 
{ 
    public static IEnumerable<DateTime> CreateTimeLine(DateTime start, TimeSpan interval) { 
     return TimeLine.CreateTimeLine(start, interval, DateTime.MaxValue); 
    } 

    public static IEnumerable<DateTime> CreateTimeLine(DateTime start, TimeSpan interval, DateTime end) { 
     var currentVal = start; 
     var endVal = end.Subtract(interval); 

     do { 
      currentVal = currentVal.Add(interval); 
      yield return currentVal; 
     } while (currentVal <= endVal); 
    } 
} 

Aby rozwiązać problem proszę Wykonaj następujące czynności:

var workingDays = TimeLine.CreateTimeLine(DateTime.Now.Date, TimeSpan.FromDays(1), DateTime.Now.Date.AddDays(30)) 
          .Where(x => x.DayOfWeek != DayOfWeek.Saturday && x.DayOfWeek != DayOfWeek.Sunday); 
var noOfWorkingDays = workingDays.Count(); 

Ta klasa linii czasu może być używana dla dowolnej linii czasu o dowolnym przedziale.

4

Napisałem rozszerzenie typu, aby umożliwić mi dodawanie (lub odejmowanie) dni tygodnia do podanej daty. Może to ci pomoże. Działa świetnie, więc zagłosuj na mój post, jeśli ci to pomoże.

/// <summary> 
    /// Adds weekdays to date 
    /// </summary> 
    /// <param name="value">DateTime to add to</param> 
    /// <param name="weekdays">Number of weekdays to add</param> 
    /// <returns>DateTime</returns> 
    public static DateTime AddWeekdays(this DateTime value, int weekdays) 
    { 
     int direction = Math.Sign(weekdays); 
     int initialDayOfWeek = Convert.ToInt32(value.DayOfWeek); 

     //--------------------------------------------------------------------------- 
     // if the day is a weekend, shift to the next weekday before calculating 
     if ((value.DayOfWeek == DayOfWeek.Sunday && direction < 0) 
      || (value.DayOfWeek == DayOfWeek.Saturday && direction > 0)) 
     { 
      value = value.AddDays(direction * 2); 
      weekdays += (direction * -1); // adjust days to add by one 
     } 
     else if ((value.DayOfWeek == DayOfWeek.Sunday && direction > 0) 
      || (value.DayOfWeek == DayOfWeek.Saturday && direction < 0)) 
     { 
      value = value.AddDays(direction); 
      weekdays += (direction * -1); // adjust days to add by one 
     } 
     //--------------------------------------------------------------------------- 

     int weeksBase = Math.Abs(weekdays/5); 
     int addDays = Math.Abs(weekdays % 5); 

     int totalDays = (weeksBase * 7) + addDays; 
     DateTime result = value.AddDays(totalDays * direction); 

     //--------------------------------------------------------------------------- 
     // if the result is a weekend, shift to the next weekday 
     if ((result.DayOfWeek == DayOfWeek.Sunday && direction > 0) 
      || (result.DayOfWeek == DayOfWeek.Saturday && direction < 0)) 
     { 
      result = result.AddDays(direction); 
     } 
     else if ((result.DayOfWeek == DayOfWeek.Sunday && direction < 0) 
      || (result.DayOfWeek == DayOfWeek.Saturday && direction > 0)) 
     { 
      result = result.AddDays(direction * 2); 
     } 
     //--------------------------------------------------------------------------- 

     return result; 
    } 
+0

Ja również Potrzebuję tego .. dziękuje dużo =) – CSharpNoob

+0

Mam wiele tego typu extenderów, które umieszczam w przestrzeni nazw Systemu, dzięki czemu są zawsze dostępne. cieszę się, że to może ci pomóc - zajęło to LONG czas, aby uzyskać prawo! :) – Brad

+0

to tylko w .. Kocham metody rozszerzenia! – jlafay

0
int count = 0; 
switch (dateTimePicker2.Value.DayOfWeek.ToString()) 
{ 
    case "Saturday": count--; break; 
    case "Sunday": count--; break; 
    default:break; 
} 
switch (dateTimePicker3.Value.DayOfWeek.ToString()) 
{ 
    case "Saturday": count--; break; 
    case "Sunday": count--; break; 
    default:break; 
} 
if (count == -2) 
    count = -1; 
int weeks = t.Days/7; 
int daycount =count+ t.Days - (2 * weeks)+1; 
label7.Text = "No of Days : " + daycount.ToString(); 
Powiązane problemy