2010-09-15 10 views
8

Ich habe Probleme damit. Ich erstelle eine Methode, die Arbeitstage an einem bestimmten Datum hinzufügt. zum Beispiel, ich möchte 3 Arbeitstage bis 15. September 2010 (Mittwoch) hinzufügen, würde die Methode September 20 (Montag nächste Woche) zurückgeben. verkennt Samstag und Sonntag, weil seine Nicht-Arbeitstag ..C#: Hinzufügen von Arbeitstagen ab einem bestimmten Datum

So etwas wie dies in C#:

DateTime AddWorkingDays(DateTime specificDate, int workingDaysToAdd) 
{ 
    return specificDate + (workingDaysToAdd - (all saturdays and sundays)) 
} 

Ich halte nicht die besonderen Urlaub auf den Berechnungen, ich buchstäblich nur wenige Tage hinzufügen möchte, außer Samstag und sonntags .. Danke im Voraus! =)

Antwort

16

Wenn Sie einen Urlaub nicht berücksichtigen müssen, würde ich vorschlagen, Sie so etwas tun:

public static DateTime AddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
{ 
    int completeWeeks = workingDaysToAdd/5; 
    DateTime date = specificDate.AddDays(completeWeeks * 7); 
    workingDaysToAdd = workingDaysToAdd % 5; 
    for (int i = 0; i < workingDaysToAdd; i++) 
    { 
     date = date.AddDays(1); 
     while (!IsWeekDay(date)) 
     { 
      date = date.AddDays(1); 
     } 
    } 
    return date; 
} 

private static bool IsWeekDay(DateTime date) 
{ 
    DayOfWeek day = date.DayOfWeek; 
    return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
} 

Es ist ineffizient, aber leicht zu verstehen. Für eine effiziente Version würden Sie die Anzahl der kompletten Wochen berechnen, die Sie hinzufügen möchten, aber dann ein Mapping von jedem "aktuellen Wochentag" und "verbleibenden Arbeitstagen" bis "Anzahl der tatsächlichen Tage bis" hinzufügen". Dann können Sie einfach die Gesamtzahl der hinzuzufügenden Tage berechnen und es in einem Anruf erledigen.

EDIT: In Bezug auf das Niveau der Ineffizienz ... es ist wirklich nicht sehr schlecht. Es werden nur manuelle "is this a weekend" Checks für bis zu 4 Tage durchgeführt, was nicht zu schlecht ist. Insbesondere ist es trotz Igor (aktuelle zum Zeitpunkt der Buchung) Ansprüche, es ist schneller als sein Ansatz, fehlerhafte Benchmarks;)

Beachten Sie, dass es möglicherweise noch nicht negative Eingaben verarbeiten - ich habe nicht überprüft.

Einer der Gründe für den Ansatz, den ich verwende, ist, dass er weder auf mich noch auf den Codeleser angewiesen ist, wenn er weiß, was die Werte in der DayOfWeek enum sind. Es ist mir egal, ob es 0-6, 1-7, Montag-Sonntag, Samstag-Freitag ... oder auch wenn es völlig bizarre Werte gibt. Ich vergleiche nur für Gleichheit, was den Code "offensichtlich korrekt" macht.

+0

Jon, wäre es effizienter sein, verwenden 'workingDaysToAdd = workingDaysToAdd% 5; Datum = Datum.AddDays (workingDaysToAdd); if (date.DayOfWeek == DayOfWeek.Samstag) date.AddDays (2); if (date.DayOfWeek == DayOfWeek.Sunday) date.AddDays (1); 'und nicht das Schleifenkonstrukt? Nur neugierig. – Lazarus

+0

Ich habe es getestet und es funktioniert genau das, was ich brauche. Hast du es spontan gemacht? in weniger als 5 Minuten, seit ich es gepostet habe .. Mann, das ist ziemlich toll .. aber ich würde mehr effiziente Antworten begrüßen .. danke btw .. – CSharpNoob

+1

Ich würde nicht sagen, es ist ineffizient, aber alle Dinge sind relativ. Die Antwort ist wochenlang gültig, also wird die Schleife höchstens 6 mal durchlaufen (max 4 für workingDays% 5, max 2 für Wochenendtage). Kein großer Erfolg. –

0

Hier ist, was Sie brauchen:

Aktualisiert:

public static DateTime AddWeekdays(DateTime start, int days) 
    { 
     int remainder = days % 5; 
     int weekendDays = (days/5) * 2; 

     DateTime end = start.AddDays(remainder); 

     if (start.DayOfWeek == DayOfWeek.Saturday && days > 0) 
     { 
      // fix for saturday. 
      end = end.AddDays(-1); 
     } 

     if (end.DayOfWeek == DayOfWeek.Saturday && days > 0) 
     { 
      // add two days for landing on saturday 
      end = end.AddDays(2); 
     } 
     else if (end.DayOfWeek < start.DayOfWeek) 
     { 
      // add two days for rounding the weekend 
      end = end.AddDays(2); 
     } 

     // add the remaining days 
     return end.AddDays(days + weekendDays - remainder); 
    } 
+0

aber der datetime Parameter (Start) kann auch Sonntag und Samstag sein .. :(.. wenn Samstag und Sonntag, muss Mittwoch der nächsten Woche zurückkehren, – CSharpNoob

+0

Ich habe gerade das getan, was du verlangst. –

+0

Ist es nicht ein bisschen zu kompliziert?Ich denke, dass es in einer viel einfacheren Weise getan werden kann – tocqueville

0
int foundWorkingDays = 0; 
while (foundWorkingDays < workingDaysToAdd) 
{ 
    specificDate= specificDate.AddDays(1); 
    if(specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday) 
    foundWorkingDays++; 

} 
return specificDate; 

ZUSÄTZLICH:

class Program 
    { 

     public static DateTime AddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
     { 
      int completeWeeks = workingDaysToAdd/5; 
      DateTime date = specificDate.AddDays(completeWeeks * 7); 
      workingDaysToAdd = workingDaysToAdd % 5; 
      for (int i = 0; i < workingDaysToAdd; i++) 
      { 
       date = date.AddDays(1); 
       while (!IsWeekDay(date)) 
       { 
        date = date.AddDays(1); 
       } 
      } 
      return date; 
     } 

     private static bool IsWeekDay(DateTime date) 
     { 
      DayOfWeek day = date.DayOfWeek; 
      return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
     } 

     public static DateTime MyAddWorkingDays(DateTime specificDate, 
             int workingDaysToAdd) 
     { 
      int foundWorkingDays = 0; 
      while (foundWorkingDays < workingDaysToAdd) 
      { 
       specificDate = specificDate.AddDays(1); 
       if (specificDate.DayOfWeek != DayOfWeek.Sunday && specificDate.DayOfWeek != DayOfWeek.Saturday) 
        foundWorkingDays++; 

      } 
      return specificDate; 
     } 


     static void Main(string[] args) 
     { 

      DateTime specificDate = DateTime.Now; 

      Stopwatch globalTimer = Stopwatch.StartNew(); 
      Console.WriteLine(AddWorkingDays(specificDate, 300)); // 100000 :) 
      globalTimer.Stop(); 
      Console.WriteLine(globalTimer.ElapsedMilliseconds); 

      globalTimer = Stopwatch.StartNew(); 
      Console.WriteLine(MyAddWorkingDays(specificDate, 300)); // 100000 :) 
      globalTimer.Stop(); 
      Console.WriteLine(globalTimer.ElapsedMilliseconds); 



      Console.ReadLine(); 
     } 
    } 
+0

Ist es effizienter als mr. Jon Skeets Vorschlag? – CSharpNoob

+0

@CSharpNoob, nein. Dies ist im Wesentlichen die gleiche Logik, ohne ganze Wochen im Voraus zu behandeln. Anstatt einer Schleife von 1 bis 4 (plus bis zu zwei Wochenendtagen) haben Sie eine Schleife von 1 bis * n * (plus * alle * Wochenendtage) –

+0

was ist der Unterschied zwischen MyAddWorkingDays und AddWorkingDays in deinem Code? – CSharpNoob

1

coole Art (glaube ich), dass in a gesetzt wird Erweiterungsmethode, wie:

public static class DateTimeExtensions 
{ 
    public static DateTime AddWorkingDays(this DateTime self, int days) 
    { 
     self = self.AddDays(days); 
     while (self.DayOfWeek == DayOfWeek.Saturday || self.DayOfWeek == DayOfWeek.Sunday) 
     { 
      self = self.AddDays(1); 
     } 

     return self; 
    } 
} 

so Ihr endgültiger Code wird wie folgt aussehen:

specificDate.AddWorkingDays(3); 
+0

es fügt nur einen Tag hinzu, selbst wenn ich 2 oder mehr Tage passiere. – CSharpNoob

+0

Wie CSharpNoob darauf hinwies, funktioniert dieser Code nicht ganz richtig, aber ich mag den Ansatz, eine Erweiterungsmethode dafür zu verwenden. – Patrick

+0

Ja, es ist falsch, ich habe nicht gut vor dem Post getestet. Entschuldigung, meine Schuld. –

-1

ist eine alte Post, aber jemand in einer Verlängerung interessiert sein könnte, die auch negative Tage behandelt.(Ich habe überarbeitet @ Jon Antwort)

public static DateTime AddWeekDays(this DateTime start, int days) 
    { 
     int direction = Math.Sign(days); 

     int completeWeeks = days/5; 
     int remaining = days % 5; 

     DateTime end = start.AddDays(completeWeeks * 7); 

     for (int i = 0; i < remaining * direction; i++) 
     { 
      end = end.AddDays(direction * 1); 
      while (!IsWeekDay(end)) 
      { 
       end = end.AddDays(direction * 1); 
      } 
     } 
     return end; 
    } 

    private static bool IsWeekDay(DateTime date) 
    { 
     DayOfWeek day = date.DayOfWeek; 
     return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday; 
    } 
0

Das scheint mir die sauberste Weg:

public static DateTime AddWorkingDays(DateTime date, int daysToAdd) 
{ 
    while (daysToAdd > 0) 
    { 
     date = date.AddDays(1); 

     if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday) daysToAdd -= 1; 
    } 

    return date; 
} 
Verwandte Themen