Recently, we got a requirement to add business days/working days to specific date considering weekends and public holidays defined in CRM system and get the next working day.
Below is the workdays and working hours defined in the CRM system:

Below are the list of holidays defined in the CRM system which are observed:

Given a specific date, we were supposed to return the next working day considering the weekends and public holidays defined as above.
Below is the block of code which can be used to meet the requirement:
/// <summary>
/// Get Next working date
/// </summary>
/// <param name="service">Organisation Service</param>
/// <param name="serviceCalenderId">GUID of service calendar</param>
/// <param name="specificDate">Date to which days need to be added</param>
/// <param name="workingDaysToAdd">Number of days to be added</param>
/// <returns>Next Working Date</returns>
public static DateTime GetNextWorkingDay(IOrganizationService service, Guid serviceCalenderId, DateTime specificDate, int workingDaysToAdd)
{
var currentDate = specificDate;
var businessClosures = GetBusinessClosureCalendarRules(service, serviceCalenderId);
// Calculate the working days by taking out the weekends(Fridays and Saturdays)
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 (!IsWorkingDayOfWeek(date))
{
date = date.AddDays(1);
}
}
// Calculate the working days by taking out public holidays
for (var i = currentDate; i <= date; i = i.AddDays(1))
{
if (i.DayOfWeek == DayOfWeek.Friday || i.DayOfWeek == DayOfWeek.Saturday)
continue;
foreach (var closure in businessClosures)
{
var startDate = (DateTime)closure["effectiveintervalstart"];
var endDate = (DateTime)closure["effectiveintervalend"];
var range = new DateRange(startDate, endDate);
if (range.Includes(i))
{
date = date.AddDays(1);
while (!IsWorkingDayOfWeek(date))
{
date = date.AddDays(1);
}
if (date.DayOfWeek == DayOfWeek.Friday)
{
date = date.AddDays(2);
while (!IsWorkingDayOfWeek(date))
{
date = date.AddDays(1);
}
i = i.AddDays(1);
}
else if (date.DayOfWeek == DayOfWeek.Saturday)
{
date = date.AddDays(1);
while (!IsWorkingDayOfWeek(date))
{
date = date.AddDays(1);
}
}
}
}
}
return date;
}
private static IEnumerable<Entity> GetBusinessClosureCalendarRules(IOrganizationService service, Guid serviceCalendarId)
{
var query = new QueryExpression("calendar")
{
ColumnSet = new ColumnSet(true),
Criteria = new FilterExpression()
};
// Add condition to get Get Calander where CalanderId is equal to Organization's businessclosurecalendarid
query.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, serviceCalendarId.ToString()));
// Get Calendar
var businessClosureCalendar = service.RetrieveMultiple(query).Entities[0];
var holidaySchedule = service.Retrieve(businessClosureCalendar.GetAttributeValue<EntityReference>("holidayschedulecalendarid").LogicalName, businessClosureCalendar.GetAttributeValue<EntityReference>("holidayschedulecalendarid").Id, new ColumnSet(true));
// Return the Calendar rules
return businessClosureCalendar != null ? holidaySchedule.GetAttributeValue<EntityCollection>("calendarrules").Entities : null;
}
private static bool IsWorkingDayOfWeek(DateTime date)
{
var day = date.DayOfWeek;
return day != DayOfWeek.Friday && day != DayOfWeek.Saturday;
}
public interface IRange<T>
{
T Start { get; }
T End { get; }
bool Includes(T value);
}
public class DateRange : IRange<DateTime>
{
public DateRange(DateTime start, DateTime end)
{
Start = start;
End = end;
}
public DateTime Start { get; private set; }
public DateTime End { get; private set; }
public bool Includes(DateTime value)
{
return (Start <= value) && (value < End);
}
}
Hope it helps !!