M a r k W o r r a l l . c o m
all articles / all Coding articles

Calculate SLA DateTime Including Weekends and Public Holidays

C# ASP.NET MVC Visual Studio 2019 SLA

Here is my solution for calculating Service Level Agreement (SLA) dates.

Given a start date and time, and number of days, it will calculate an end date based on business hours only.

It takes into account weekends and public holidays (the list of public holidays is held in an in-memory cache).

It uses 2 TimeSpan objects that define what time the workday starts and ends.


public DateTime? CalculateSLADueDate(DateTime slaStartDateUTC, double slaDays, TimeSpan workdayStartUTC, TimeSpan workdayEndUTC)
{
  if ((slaDays < 0)
  || (workdayStartUTC > workdayEndUTC))
  {
    return null;
  }

  var dueDate = slaStartDateUTC;
  var tsWorkdayHours = (workdayEndUTC - workdayStartUTC);
  var tsSlaCount = TimeSpan.FromHours(slaDays * ((workdayEndUTC - workdayStartUTC)).TotalHours);

  //get list of public holidays from in-memory cache
  var blPublicHoliday = new PublicHoliday();
  IList publicHolidays = blPublicHoliday.SelectAll();

  do
  {
    if ((dueDate.DayOfWeek == DayOfWeek.Saturday)
    || (dueDate.DayOfWeek == DayOfWeek.Sunday)
    || publicHolidays.Any(x => x.HolidayDate == dueDate.Date)
    || ((dueDate.TimeOfDay >= workdayEndUTC) && (dueDate.TimeOfDay < workdayStartUTC)))
    {
      //jump to start of next day
      dueDate = dueDate.AddDays(1);
      dueDate = new DateTime(dueDate.Year, dueDate.Month, dueDate.Day, workdayStartUTC.Hours, workdayStartUTC.Minutes, workdayStartUTC.Seconds);
    }
    else if ((dueDate.TimeOfDay == workdayStartUTC) && (tsSlaCount >= tsWorkdayHours))
    {
      //add a whole working day
      dueDate = dueDate.AddDays(1);
      tsSlaCount = tsSlaCount.Subtract(tsWorkdayHours);
    }
    else if (dueDate.TimeOfDay == workdayStartUTC)
    {
      //end day - add remainder of time for final work day
      dueDate = dueDate.Add(tsSlaCount);
      tsSlaCount = tsSlaCount.Subtract(tsSlaCount);
    }
    else
    {
      if(workdayEndUTC > dueDate.TimeOfDay)
      {
        //start day and still in business hours - add rest of today
        tsSlaCount = tsSlaCount.Subtract(workdayEndUTC - dueDate.TimeOfDay);
        dueDate = dueDate.Add(workdayEndUTC - dueDate.TimeOfDay);
      }

      if (tsSlaCount.Ticks > 0)
      {
        //if theres more to process - jump to start of next day
        dueDate = dueDate.AddDays(1);
        dueDate = new DateTime(dueDate.Year, dueDate.Month, dueDate.Day, workdayStartUTC.Hours, workdayStartUTC.Minutes, workdayStartUTC.Seconds);
      }
    }
  }
  while (tsSlaCount.Ticks > 0);

  return dueDate;
}






Add Comment

*

*

*

capthca1 capthca2 capthca3 capthca4 capthca5 capthca6

*