AddBusinessDays and GetBusinessDays

I need to find two elegant complete implementations

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) is preferred (no loops).

EDIT: By working days, I mean working days (Monday, Tuesday, Wednesday, Thursday, Friday). No holidays, only weekends excluded.

I already have some ugly solutions that seem to work, but I wonder if there are elegant ways to do this. Thanks




This is what I wrote so far. It works in all cases and makes negatives. Still Need GetBusinessDays Implementation

 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); } 
+83
c #
Jun 25 '09 at 15:48
source share
15 answers

Last try for your first 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); } 

The second GetBusinessDays function can be implemented as follows:

 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; } } 
+128
Jun 25 '09 at 16:14
source share

using Fluent DateTime :

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

the internal code is as follows

  /// <summary> /// Adds the given number of business days to the <see cref="DateTime"/>. /// </summary> /// <param name="current">The date to be changed.</param> /// <param name="days">Number of business days to be added.</param> /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns> 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; } /// <summary> /// Subtracts the given number of business days to the <see cref="DateTime"/>. /// </summary> /// <param name="current">The date to be changed.</param> /// <param name="days">Number of business days to be subtracted.</param> /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns> public static DateTime SubtractBusinessDays(this DateTime current, int days) { return AddBusinessDays(current, -days); } 
+59
Sep 04 '09 at 13:12
source share

I created an extension that allows you to add or subtract business days. Use a negative number of businessDays to subtract. I think this is a pretty elegant solution. It seems to work in all cases.

 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); } } } 

Example:

 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(); } } } 
+12
Aug 6 '13 at
source share

For me, I had to have a solution that would skip the weekend and go either negatively or positively. My criteria were that if they went ahead and landed on the weekend, it should have progressed on Monday. If he returns and lands on the weekend, he will have to jump on Friday.

For example:

  • Wednesday - 3 business days = Last Friday
  • Wednesday + 3 business days = Monday
  • Friday - 7 business days = Last Wednesday
  • tuesday - 5 business days = last tuesday

Well, you get the idea;)

I wrote this class of extensions

 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; } } 

He uses this method, which I thought was useful to use elsewhere ...

 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; } } } 

If you don't want to worry about this, you can simply replace if (MyClass.IsBusinessDay(date)) with if if ((date.DayOfWeek != DayOfWeek.Saturday) && (date.DayOfWeek != DayOfWeek.Sunday))

So now you can do

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

or

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

The following are some test results:

 Test Expected Result
 Wednesday -4 business days Thursday Thursday
 Wednesday -3 business days Friday Friday
 Wednesday +3 business days Monday Monday
 Friday -7 business days Wednesday Wednesday
 Tuesday -5 business days Tuesday Tuesday
 Friday +1 business days Monday Monday
 Saturday +1 business days Monday Monday
 Sunday -1 business days Friday Friday
 Monday -1 business days Friday Friday
 Monday +1 business days Tuesday Tuesday
 Monday +0 business days Monday Monday
+8
Sep 17 '15 at 15:27
source share

With internationalization, it is difficult. As mentioned in other sections here at SOF, holidays differ from country to country, of course, and even from province to province. Most governments do not plan their vacations for more than five years or so.

+2
Jun 25 '09 at 16:04
source share

The only real solution is to make these calls access the database table that defines the calendar for your company. You can program it for the work week from Monday to Friday without much difficulty, but handling the holidays will be a problem.

Edited to add an unaesthetic and untested partial solution:

 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; } 

I also violated the requirement of no loops.

+1
Jun 25 '09 at 15:57
source share
 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); } 
+1
Jun 25 '09 at 16:42
source share

I am late for an answer, but I created a small library with all the settings necessary to perform simple operations on weekdays ... I leave it here: Manage weekdays

+1
Apr 08 '16 at 1:56
source share
  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; } 
0
Sep 16 '13 at 18:51
source share

I need "AddBusinessDays" that supported negative numbers of days to add, and I ended up with this:

 // 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 } 

No cycle is required, so it should be fast enough even for "big" additions.

It works with days, expressed as the number of calendar days from the era, since it was discovered by the new JDK8 LocalDate class, and I worked in Java. It should just be adaptable to other settings.

The main properties are that addDays always returns the day of the week, and for all d and n , daysBetween(d, addDays(d, n)) == n

Please note that theoretically, adding 0 days and subtracting 0 days should have different operations (if your date is Sunday, adding 0 days should lead you to Monday, and subtracting 0 days should take you until Friday). Since there is no such thing as negative 0 (outside the floating point!), I decided to interpret the argument n = 0, since that means adding zero days.

0
Dec 02 '15 at 23:01
source share

I believe this may be an easier way to GetBusinessDays:

  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; } 
0
Jun 03 '16 at 15:21
source share

Here is my code with the date of departure and date of delivery at the client.

  // 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; 

Happy coding.

0
Oct 19 '16 at 20:40
source share
 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; } 
0
Aug 21 '17 at 18:12
source share

I am resurrecting this post because today I had to find a way to exclude not only Saturday and Sunday, but also holidays. More specifically, I needed to handle various sets of possible holidays, including:

  • country-independent holidays (at least for Western countries - for example, January 01).
  • calculated holidays (e.g. Easter and Easter Monday).
  • Holidays for a specific country (for example, the day of the liberation of Italy or ID4 USA).
  • City holidays (for example, the patron saint day of Rome).
  • any other custom holiday (for example, "tomorrow our office will be closed").

In the end, I came out with the following set of helper / extension classes: although they don't look clearly elegant because they use inefficient loops widely, they are decent enough to solve my problems forever. I omit all the source code here in this post, hoping it will be useful to someone else as well.

Source

 /// <summary> /// Helper/extension class for manipulating date and time values. /// </summary> public static class DateTimeExtensions { /// <summary> /// Calculates the absolute year difference between two dates. /// </summary> /// <param name="dt1"></param> /// <param name="dt2"></param> /// <returns>A whole number representing the number of full years between the specified dates.</returns> public static int Years(DateTime dt1,DateTime dt2) { return Months(dt1,dt2)/12; //if (dt2<dt1) //{ // DateTime dt0=dt1; // dt1=dt2; // dt2=dt0; //} //int diff=dt2.Year-dt1.Year; //int m1=dt1.Month; //int m2=dt2.Month; //if (m2>m1) return diff; //if (m2==m1 && dt2.Day>=dt1.Day) return diff; //return (diff-1); } /// <summary> /// Calculates the absolute year difference between two dates. /// Alternative, stand-alone version (without other DateTimeUtil dependency nesting required) /// </summary> /// <param name="start"></param> /// <param name="end"></param> /// <returns></returns> public static int Years2(DateTime start, DateTime end) { return (end.Year - start.Year - 1) + (((end.Month > start.Month) || ((end.Month == start.Month) && (end.Day >= start.Day))) ? 1 : 0); } /// <summary> /// Calculates the absolute month difference between two dates. /// </summary> /// <param name="dt1"></param> /// <param name="dt2"></param> /// <returns>A whole number representing the number of full months between the specified dates.</returns> public static int Months(DateTime dt1,DateTime dt2) { if (dt2<dt1) { DateTime dt0=dt1; dt1=dt2; dt2=dt0; } dt2=dt2.AddDays(-(dt1.Day-1)); return (dt2.Year-dt1.Year)*12+(dt2.Month-dt1.Month); } /// <summary> /// Returns the higher of the two date time values. /// </summary> /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param> /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param> /// <returns><c>dt1</c> or <c>dt2</c>, whichever is higher.</returns> public static DateTime Max(DateTime dt1,DateTime dt2) { return (dt2>dt1?dt2:dt1); } /// <summary> /// Returns the lower of the two date time values. /// </summary> /// <param name="dt1">The first of the two <c>DateTime</c> values to compare.</param> /// <param name="dt2">The second of the two <c>DateTime</c> values to compare.</param> /// <returns><c>dt1</c> or <c>dt2</c>, whichever is lower.</returns> public static DateTime Min(DateTime dt1,DateTime dt2) { return (dt2<dt1?dt2:dt1); } /// <summary> /// Adds the given number of business days to the <see cref="DateTime"/>. /// </summary> /// <param name="current">The date to be changed.</param> /// <param name="days">Number of business days to be added.</param> /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param> /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns> public static DateTime AddBusinessDays( this DateTime current, int days, IEnumerable<DateTime> holidays = null) { 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 || (holidays != null && holidays.Contains(current.Date)) ); } return current; } /// <summary> /// Subtracts the given number of business days to the <see cref="DateTime"/>. /// </summary> /// <param name="current">The date to be changed.</param> /// <param name="days">Number of business days to be subtracted.</param> /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param> /// <returns>A <see cref="DateTime"/> increased by a given number of business days.</returns> public static DateTime SubtractBusinessDays( this DateTime current, int days, IEnumerable<DateTime> holidays) { return AddBusinessDays(current, -days, holidays); } /// <summary> /// Retrieves the number of business days from two dates /// </summary> /// <param name="startDate">The inclusive start date</param> /// <param name="endDate">The inclusive end date</param> /// <param name="holidays">An optional list of holiday (non-business) days to consider.</param> /// <returns></returns> public static int GetBusinessDays( this DateTime startDate, DateTime endDate, IEnumerable<DateTime> holidays) { if (startDate > endDate) throw new NotSupportedException("ERROR: [startDate] cannot be greater than [endDate]."); int cnt = 0; for (var current = startDate; current < endDate; current = current.AddDays(1)) { if (current.DayOfWeek == DayOfWeek.Saturday || current.DayOfWeek == DayOfWeek.Sunday || (holidays != null && holidays.Contains(current.Date)) ) { // skip holiday } else cnt++; } return cnt; } /// <summary> /// Calculate Easter Sunday for any given year. /// src.: https://stackoverflow.com/a/2510411/1233379 /// </summary> /// <param name="year">The year to calcolate Easter against.</param> /// <returns>a DateTime object containing the Easter month and day for the given year</returns> public static DateTime GetEasterSunday(int year) { int day = 0; int month = 0; int g = year % 19; int c = year / 100; int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30; int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11)); day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28; month = 3; if (day > 31) { month++; day -= 31; } return new DateTime(year, month, day); } /// <summary> /// Retrieve holidays for given years /// </summary> /// <param name="years">an array of years to retrieve the holidays</param> /// <param name="countryCode">a country two letter ISO (ex.: "IT") to add the holidays specific for that country</param> /// <param name="cityName">a city name to add the holidays specific for that city</param> /// <returns></returns> public static IEnumerable<DateTime> GetHolidays(IEnumerable<int> years, string countryCode = null, string cityName = null) { var lst = new List<DateTime>(); foreach (var year in years.Distinct()) { lst.AddRange(new[] { new DateTime(year, 1, 1), // 1 gennaio (capodanno) new DateTime(year, 1, 6), // 6 gennaio (epifania) new DateTime(year, 5, 1), // 1 maggio (lavoro) new DateTime(year, 8, 15), // 15 agosto (ferragosto) new DateTime(year, 11, 1), // 1 novembre (ognissanti) new DateTime(year, 12, 8), // 8 dicembre (immacolata concezione) new DateTime(year, 12, 25), // 25 dicembre (natale) new DateTime(year, 12, 26) // 26 dicembre (s. stefano) }); // add easter sunday (pasqua) and monday (pasquetta) var easterDate = GetEasterSunday(year); lst.Add(easterDate); lst.Add(easterDate.AddDays(1)); // country-specific holidays if (!String.IsNullOrEmpty(countryCode)) { switch (countryCode.ToUpper()) { case "IT": lst.Add(new DateTime(year, 4, 25)); // 25 aprile (liberazione) break; case "US": lst.Add(new DateTime(year, 7, 4)); // 4 luglio (Independence Day) break; // todo: add other countries case default: // unsupported country: do nothing break; } } // city-specific holidays if (!String.IsNullOrEmpty(cityName)) { switch (cityName) { case "Rome": case "Roma": lst.Add(new DateTime(year, 6, 29)); // 29 giugno (s. pietro e paolo) break; case "Milano": case "Milan": lst.Add(new DateTime(year, 12, 7)); // 7 dicembre (s. ambrogio) break; // todo: add other cities default: // unsupported city: do nothing break; } } } return lst; } } 

Usage Information

The code is pretty straightforward, however here are a couple of examples to explain how you can use it.

Add 10 business days (skipping only Saturday and Sunday)

 var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10); 

Add 10 business days (skipping Saturday, Sunday, and all country-independent holidays for 2019)

 var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019)); 

Add 10 business days (skipping Saturday, Sunday, and all Italian holidays for 2019)

 var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT")); 

Add 10 business days (skipping Saturday, Sunday, all Italian holidays and holidays in Rome in 2019)

 var dtResult = DateTimeUtil.AddBusinessDays(srcDate, 10, GetHolidays(2019, "IT", "Rome")); 

The above functions and code examples are described in more detail in this post of my blog.

0
Jun 19 '19 at 13:46
source share

Hope this helps someone.

 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; } 
-one
Aug 15 '13 at 16:47
source share



All Articles