AddBusinessDays und GetBusinessDays

Ich muss 2 elegante vollständige Implementierungen von finden

public static DateTime AddBusinessDays(this DateTime date, int days) { // code here } and public static int GetBusinessDays(this DateTime start, DateTime end) { // code here } 

O (1) vorzuziehen (keine Schleifen).

EDIT: Werktags meine ich Arbeitstage (Montag, Dienstag, Mittwoch, Donnerstag, Freitag). Keine Ferien, nur Wochenenden ausgeschlossen.

Ich habe bereits einige hässliche Lösungen, die zu funktionieren scheinen, aber ich frage mich, ob es elegante Möglichkeiten gibt, dies zu tun. Vielen Dank


Das habe ich bisher geschrieben. Es funktioniert in allen Fällen und macht auch Negative. Benötigen Sie noch eine GetBusinessDays-Implementierung

 public static DateTime AddBusinessDays(this DateTime startDate, int businessDays) { int direction = Math.Sign(businessDays); if(direction == 1) { if(startDate.DayOfWeek == DayOfWeek.Saturday) { startDate = startDate.AddDays(2); businessDays = businessDays - 1; } else if(startDate.DayOfWeek == DayOfWeek.Sunday) { startDate = startDate.AddDays(1); businessDays = businessDays - 1; } } else { if(startDate.DayOfWeek == DayOfWeek.Saturday) { startDate = startDate.AddDays(-1); businessDays = businessDays + 1; } else if(startDate.DayOfWeek == DayOfWeek.Sunday) { startDate = startDate.AddDays(-2); businessDays = businessDays + 1; } } int initialDayOfWeek = (int)startDate.DayOfWeek; int weeksBase = Math.Abs(businessDays / 5); int addDays = Math.Abs(businessDays % 5); if((direction == 1 && addDays + initialDayOfWeek > 5) || (direction == -1 && addDays >= initialDayOfWeek)) { addDays += 2; } int totalDays = (weeksBase * 7) + addDays; return startDate.AddDays(totalDays * direction); } 

Solutions Collecting From Web of "AddBusinessDays und GetBusinessDays"

Letzter Versuch für Ihre erste function:

 public static DateTime AddBusinessDays(DateTime date, int days) { if (days < 0) { throw new ArgumentException("days cannot be negative", "days"); } if (days == 0) return date; if (date.DayOfWeek == DayOfWeek.Saturday) { date = date.AddDays(2); days -= 1; } else if (date.DayOfWeek == DayOfWeek.Sunday) { date = date.AddDays(1); days -= 1; } date = date.AddDays(days / 5 * 7); int extraDays = days % 5; if ((int)date.DayOfWeek + extraDays > 5) { extraDays += 2; } return date.AddDays(extraDays); } 

Die zweite function, GetBusinessDays, kann wie folgt implementiert werden:

 public static int GetBusinessDays(DateTime start, DateTime end) { if (start.DayOfWeek == DayOfWeek.Saturday) { start = start.AddDays(2); } else if (start.DayOfWeek == DayOfWeek.Sunday) { start = start.AddDays(1); } if (end.DayOfWeek == DayOfWeek.Saturday) { end = end.AddDays(-1); } else if (end.DayOfWeek == DayOfWeek.Sunday) { end = end.AddDays(-2); } int diff = (int)end.Subtract(start).TotalDays; int result = diff / 7 * 5 + diff % 7; if (end.DayOfWeek < start.DayOfWeek) { return result - 2; } else{ return result; } } 

Fluent DateTime verwenden :

 var now = DateTime.Now; var dateTime1 = now.AddBusinessDays(3); var dateTime2 = now.SubtractBusinessDays(5); 

interner Code ist wie folgt

  ///  /// Adds the given number of business days to the . ///  /// The date to be changed. /// Number of business days to be added. /// A  increased by a given number of business days. public static DateTime AddBusinessDays(this DateTime current, int days) { var sign = Math.Sign(days); var unsignedDays = Math.Abs(days); for (var i = 0; i < unsignedDays; i++) { do { current = current.AddDays(sign); } while (current.DayOfWeek == DayOfWeek.Saturday || current.DayOfWeek == DayOfWeek.Sunday); } return current; } ///  /// Subtracts the given number of business days to the . ///  /// The date to be changed. /// Number of business days to be subtracted. /// A  increased by a given number of business days. public static DateTime SubtractBusinessDays(this DateTime current, int days) { return AddBusinessDays(current, -days); } 

Ich habe eine Erweiterung erstellt, mit der Sie Geschäftstage hinzufügen oder subtrahieren können. Verwenden Sie eine negative Anzahl von businessDays zum Subtrahieren. Ich denke, es ist eine ziemlich elegante Lösung. Es scheint in allen Fällen zu funktionieren.

 namespace Extensions.DateTime { public static class BusinessDays { public static System.DateTime AddBusinessDays(this System.DateTime source, int businessDays) { var dayOfWeek = businessDays < 0 ? ((int)source.DayOfWeek - 12) % 7 : ((int)source.DayOfWeek + 6) % 7; switch (dayOfWeek) { case 6: businessDays--; break; case -6: businessDays++; break; } return source.AddDays(businessDays + ((businessDays + dayOfWeek) / 5) * 2); } } } 

Beispiel:

 using System; using System.Windows.Forms; using Extensions.DateTime; namespace AddBusinessDaysTest { public partial class Form1 : Form { public Form1() { InitializeComponent(); label1.Text = DateTime.Now.AddBusinessDays(5).ToString(); label2.Text = DateTime.Now.AddBusinessDays(-36).ToString(); } } } 

Für mich musste ich eine Lösung haben, die Wochenenden übersprang und entweder negativ oder positiv ging. Meine Kriterien waren, wenn es vorwärts ging und an einem Wochenende landete, müsste es bis Montag vorrücken. Wenn es zurückgehen und an einem Wochenende landen würde, müsste es bis Freitag springen.

Beispielsweise:

  • Mittwoch – 3 Werktage = Letzter Freitag
  • Mittwoch + 3 Werktage = Montag
  • Freitag – 7 Werktage = Letzter Mittwoch
  • Dienstag – 5 Werktage = Letzter Dienstag

Nun, du hast die Idee;)

Ich habe diese Erweiterungsklasse geschrieben

 public static partial class MyExtensions { public static DateTime AddBusinessDays(this DateTime date, int addDays) { while (addDays != 0) { date = date.AddDays(Math.Sign(addDays)); if (MyClass.IsBusinessDay(date)) { addDays = addDays - Math.Sign(addDays); } } return date; } } 

Es verwendet diese Methode, von der ich dachte, dass sie nützlich wäre, woanders zu verwenden …

 public class MyClass { public static bool IsBusinessDay(DateTime date) { switch (date.DayOfWeek) { case DayOfWeek.Monday: case DayOfWeek.Tuesday: case DayOfWeek.Wednesday: case DayOfWeek.Thursday: case DayOfWeek.Friday: return true; default: return false; } } } 

Wenn Sie sich nicht damit beschäftigen wollen, können Sie einfach if (MyClass.IsBusinessDay(date)) durch if if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday)) ersetzen if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

Jetzt kannst du es tun

 var myDate = DateTime.Now.AddBusinessDays(-3); 

oder

 var myDate = DateTime.Now.AddBusinessDays(5); 

Hier sind die Ergebnisse einiger Tests:

 Test Erwartetes Ergebnis
 Mittwoch -4 Werktage Donnerstag Donnerstag
 Mittwoch -3 Werktage Freitag, Freitag
 Mittwoch +3 Werktage Montag Montag
 Freitag -7 Werktage Mittwoch Mittwoch
 Dienstag -5 Werktage Dienstag Dienstag
 Freitag +1 Werktage Montag Montag
 Samstag +1 Werktage Montag Montag
 Sonntag -1 Werktage Freitag Freitag
 Montag -1 Werktage Freitag Freitag
 Montag +1 Werktage Dienstag Dienstag
 Montag +0 Werktage Montag Montag

Mit der Internationalisierung ist das schwierig. Wie in anderen Themen hier auf SOF erwähnt, unterscheiden sich Feiertage von Land zu Land und sogar von Provinz zu Provinz. Die meisten Regierungen planen ihre Ferien nicht mehr als fünf Jahre oder so.

 public static DateTime AddBusinessDays(this DateTime date, int days) { date = date.AddDays((days / 5) * 7); int remainder = days % 5; switch (date.DayOfWeek) { case DayOfWeek.Tuesday: if (remainder > 3) date = date.AddDays(2); break; case DayOfWeek.Wednesday: if (remainder > 2) date = date.AddDays(2); break; case DayOfWeek.Thursday: if (remainder > 1) date = date.AddDays(2); break; case DayOfWeek.Friday: if (remainder > 0) date = date.AddDays(2); break; case DayOfWeek.Saturday: if (days > 0) date = date.AddDays((remainder == 0) ? 2 : 1); break; case DayOfWeek.Sunday: if (days > 0) date = date.AddDays((remainder == 0) ? 1 : 0); break; default: // monday break; } return date.AddDays(remainder); } 

Ich komme zu spät für die Antwort, aber ich habe eine kleine Bibliothek mit all den Anpassungen erstellt, die benötigt werden, um einfache Operationen an Arbeitstagen durchzuführen … Ich verlasse es hier: Working Days Management

  public static DateTime AddBusinessDays(DateTime date, int days) { if (days == 0) return date; int i = 0; while (i < days) { if (!(date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday)) i++; date = date.AddDays(1); } return date; } 

Ich wollte einen “AddBusinessDays”, der eine negative Anzahl von Tagen zum Hinzufügen unterstützt, und ich endete damit:

 // 0 == Monday, 6 == Sunday private static int epochDayToDayOfWeek0Based(long epochDay) { return (int)Math.floorMod(epochDay + 3, 7); } public static int daysBetween(long fromEpochDay, long toEpochDay) { // http://stackoverflow.com/questions/1617049/calculate-the-number-of-business-days-between-two-dates final int fromDOW = epochDayToDayOfWeek0Based(fromEpochDay); final int toDOW = epochDayToDayOfWeek0Based(toEpochDay); long calcBusinessDays = ((toEpochDay - fromEpochDay) * 5 + (toDOW - fromDOW) * 2) / 7; if (toDOW == 6) calcBusinessDays -= 1; if (fromDOW == 6) calcBusinessDays += 1; return (int)calcBusinessDays; } public static long addDays(long epochDay, int n) { // https://alecpojidaev.wordpress.com/2009/10/29/work-days-calculation-with-c/ // NB: in .NET, Sunday == 0, but in our code Monday == 0 final int dow = (epochDayToDayOfWeek0Based(epochDay) + 1) % 7; final int wds = n + (dow == 0 ? 1 : dow); // Adjusted number of working days to add, given that we now start from the immediately preceding Sunday final int wends = n < 0 ? ((wds - 5) / 5) * 2 : (wds / 5) * 2 - (wds % 5 == 0 ? 2 : 0); return epochDay - dow + // Find the immediately preceding Sunday wds + // Add computed working days wends; // Add weekends that occur within each complete working week } 

Keine Schleife erforderlich, daher sollte es selbst für "große" Additionen ziemlich schnell sein.

Es funktioniert mit Tagen, die in einer Anzahl von Kalendertagen seit der Epoche ausgedrückt werden, da dies durch die neue JDK8 LocalDate class offen gelegt wird und ich in Java gearbeitet habe. Sollte sich jedoch leicht an andere Einstellungen anpassen.

Die grundlegenden Eigenschaften sind, dass addDays immer einen Wochentag zurückgibt, und das für alle d und n , daysBetween(d, addDays(d, n)) == n

Beachten Sie, dass theoretisch das Hinzufügen von 0 Tagen und das Subtrahieren von 0 Tagen unterschiedliche Operationen sein sollten (wenn Ihr Datum ein Sonntag ist, sollten Sie 0 Tage zu Montag hinzufügen, und das Subtrahieren von 0 Tagen sollte Sie zu Freitag bringen). Da es keine negative 0 gibt (außerhalb des Fließkommas!), Habe ich entschieden, ein Argument n = 0 so zu interpretieren , dass es null Tage addiert .

Ich glaube, dies könnte ein einfacher Weg zu GetBusinessDays sein:

  public int GetBusinessDays(DateTime start, DateTime end, params DateTime[] bankHolidays) { int tld = (int)((end - start).TotalDays) + 1; //including end day int not_buss_day = 2 * (tld / 7); //Saturday and Sunday int rest = tld % 7; //rest. if (rest > 0) { int tmp = (int)start.DayOfWeek - 1 + rest; if (tmp == 6 || start.DayOfWeek == DayOfWeek.Sunday) not_buss_day++; else if (tmp > 6) not_buss_day += 2; } foreach (DateTime bankHoliday in bankHolidays) { DateTime bh = bankHoliday.Date; if (!(bh.DayOfWeek == DayOfWeek.Saturday || bh.DayOfWeek == DayOfWeek.Sunday) && (start < = bh && bh <= end)) { not_buss_day++; } } return tld - not_buss_day; } 

Die einzige echte Lösung besteht darin, dass diese Aufrufe auf eine databasetabelle zugreifen, die den Kalender für Ihr Unternehmen definiert. Sie könnten es für eine Arbeitswoche von Montag bis Freitag programmieren, ohne zu viel Schwierigkeiten zu machen, aber die Abwicklung von Ferien wäre eine Herausforderung.

Bearbeitet, um nicht-elegante und nicht-getestete Teillösung hinzuzufügen:

 public static DateTime AddBusinessDays(this DateTime date, int days) { for (int index = 0; index < days; index++) { switch (date.DayOfWeek) { case DayOfWeek.Friday: date = date.AddDays(3); break; case DayOfWeek.Saturday: date = date.AddDays(2); break; default: date = date.AddDays(1); break; } } return date; } 

Auch ich habe die No-Loops-Anforderung verletzt.

Hier ist mein Code mit Abfahrtsdatum und Lieferdatum beim Kunden.

  // Calculate departure date TimeSpan DeliveryTime = new TimeSpan(14, 30, 0); TimeSpan now = DateTime.Now.TimeOfDay; DateTime dt = DateTime.Now; if (dt.TimeOfDay > DeliveryTime) dt = dt.AddDays(1); if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1); if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1); dt = dt.Date + DeliveryTime; string DepartureDay = "today at "+dt.ToString("HH:mm"); if (dt.Day!=DateTime.Now.Day) { DepartureDay = dt.ToString("dddd at HH:mm", new CultureInfo(WebContextState.CurrentUICulture)); } Return DepartureDay; // Caclulate delivery date dt = dt.AddDays(1); if (dt.DayOfWeek == DayOfWeek.Saturday) dt = dt.AddDays(1); if (dt.DayOfWeek == DayOfWeek.Sunday) dt = dt.AddDays(1); string DeliveryDay = dt.ToString("dddd", new CultureInfo(WebContextState.CurrentUICulture)); return DeliveryDay; 

Glückliche Kodierung.

 public static DateTime AddWorkingDays(this DateTime date, int daysToAdd) { while (daysToAdd > 0) { date = date.AddDays(1); if (date.DayOfWeek != DayOfWeek.Saturday && date.DayOfWeek != DayOfWeek.Sunday) { daysToAdd -= 1; } } return date; } 

Hoffe, das hilft jemandem.

 private DateTime AddWorkingDays(DateTime addToDate, int numberofDays) { addToDate= addToDate.AddDays(numberofDays); while (addToDate.DayOfWeek == DayOfWeek.Saturday || addToDate.DayOfWeek == DayOfWeek.Sunday) { addToDate= addToDate.AddDays(1); } return addToDate; }