locked
How to exclude holidays from Date schedules RRS feed

  • Question

  • User457850011 posted

    I am scheduling a weekly and monthly events. When the schedule Date falls on a holiday, I either want to move the date one day forward or exclude the holiday. My code is not working. Below is my solution. Any help will be appreciated.

    using System;
    using System.Collections.Generic;
    using System.Linq;

    namespace SeriesTest
    {
    class Program
    {
    public class BusinessWeekDays
    {
    public DateTime Monday;
    public DateTime Sunday;
    }

    private static HashSet<DateTime> GetHolidays(int year)
    {
    var holidays = new HashSet<DateTime>();

    var newYearsDate = AdjustForWeekendHoliday(new DateTime(year, 1, 1).Date);
    holidays.Add(newYearsDate);
    var memorialDay = new DateTime(year, 5, 31);
    var dayOfWeek = memorialDay.DayOfWeek;
    while (dayOfWeek != DayOfWeek.Monday)
    {
    memorialDay = memorialDay.AddDays(-1);
    dayOfWeek = memorialDay.DayOfWeek;
    }

    holidays.Add(memorialDay.Date);
    var independenceDay = AdjustForWeekendHoliday(new DateTime(year, 7, 4).Date);
    holidays.Add(independenceDay);
    var laborDay = new DateTime(year, 9, 1);
    dayOfWeek = laborDay.DayOfWeek;
    while (dayOfWeek != DayOfWeek.Monday)
    {
    laborDay = laborDay.AddDays(1);
    dayOfWeek = laborDay.DayOfWeek;
    }

    holidays.Add(laborDay.Date);
    var thanksgiving = (from day in Enumerable.Range(1, 30)
    where new DateTime(year, 11, day).DayOfWeek == DayOfWeek.Thursday
    select day).ElementAt(3);
    var thanksgivingDay = new DateTime(year, 11, thanksgiving);
    holidays.Add(thanksgivingDay.Date);

    var christmasDay = AdjustForWeekendHoliday(new DateTime(year, 12, 25).Date);
    holidays.Add(christmasDay);
    var MLKDay = new DateTime(year, 1, 21);
    dayOfWeek = MLKDay.DayOfWeek;
    while (dayOfWeek != DayOfWeek.Monday)
    {
    MLKDay = MLKDay.AddDays(-1);
    dayOfWeek = MLKDay.DayOfWeek;
    }

    holidays.Add(MLKDay.Date);

    var PresDay = new DateTime(year, 2, 21);
    dayOfWeek = PresDay.DayOfWeek;
    while (dayOfWeek != DayOfWeek.Monday)
    {
    PresDay = PresDay.AddDays(-1);
    dayOfWeek = PresDay.DayOfWeek;
    }

    holidays.Add(PresDay.Date);
    var LincolnsBday = AdjustForWeekendHoliday(new DateTime(year, 2, 12).Date);
    holidays.Add(LincolnsBday);

    var Veternsday = new DateTime(year, 11, 11).Date;
    holidays.Add(Veternsday);

    var columbusday = new DateTime(year, 10, 14);
    dayOfWeek = columbusday.DayOfWeek;
    while (dayOfWeek != DayOfWeek.Monday)
    {
    columbusday = columbusday.AddDays(-1);
    dayOfWeek = columbusday.DayOfWeek;
    }

    holidays.Add(columbusday.Date);


    return holidays;
    }

    public static DateTime AdjustForWeekendHoliday(DateTime holiday)
    {
    switch (holiday.DayOfWeek)
    {
    case DayOfWeek.Saturday:
    return holiday.AddDays(-1);
    case DayOfWeek.Sunday:
    return holiday.AddDays(1);
    default:
    return holiday;
    }
    }

     

    static void Main(string[] args)
    {


    var StartDate = DateTime.Parse("06/27/2019");
    var SeriesEndDate = DateTime.Parse("07/30/2019");

    var currentyear = DateTime.Now.Year;
    var GH = GetHolidays(currentyear);
    var firstMonday = Enumerable.Range(0, 7)
    .Select(x => StartDate.AddDays(x))
    .First();
    var ts = (SeriesEndDate - StartDate);

    var dates = new List<BusinessWeekDays>();

    for (var i = 0; i < ts.Days; i += 7)
    {
    foreach (var q in GH)
    {
    if (q.Date != StartDate || q.Date != SeriesEndDate)
    {
    dates.Add(new BusinessWeekDays
    { Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 7) });

    }
    }

    Console.WriteLine(dates);
    }
    }
    }
    }







    Friday, April 5, 2019 3:27 PM

Answers

  • User475983607 posted

    I agree but this portion doesn't seems to do what I want

    for (var i = 0; i < ts.Days; i += 7)
    {
    if (BusinessDays(StartDate, SeriesEndDate, new List<DateTime>(GetHolidays(currentyear))) != 0)
    {
    dates.Add(new BusinessWeekDays
    {Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 7)});
    }
    }

    You have not explained what you want and I do not understand the code.

    Here is a basic example of removing a holiday.

            static void Main(string[] args)
            {
    
                List<DateTime> holidays = new List<DateTime>() { new DateTime(2019, 7, 4) };
    
    
                var StartDate = DateTime.Parse("06/27/2019");
                var SeriesEndDate = DateTime.Parse("07/30/2019");
    
                List<DateTime> results = Enumerable.Range(0, 1 + SeriesEndDate.Subtract(StartDate).Days)
                    .Select(offset => StartDate.AddDays(offset))
                    .ToList();
    
                foreach(var item in holidays)
                {
                    results.Remove(item);
                }
    
                foreach(var result in results)
                {
                    Console.WriteLine(result);
                }
    
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, April 5, 2019 6:08 PM

All replies

  • User475983607 posted

    I'm trying to make sense of the code and it seems you are trying to programmatically calculate the workday a holiday is observed? I would enter both manually into a record.  You can always run a date through a method to calculate the observed day as long as the requirement is well defined.  Either way you want both dates in a record.

    Once you have holidays then it's just a matter of querying the table to fetch the holidays that fall within a range.  Simply return this information to the user and let them decided what to do.  If you want the system to make the decision, then you need to add a more information to the table so the code knows what to do.

    Friday, April 5, 2019 4:06 PM
  • User457850011 posted

    Hi

    Thanks for your response. Yes, I am not sure if I understand what you mean by "run date through a method" . My HashSet<DateTime> GetHolidays is doing exactly what you are saying. I am getting the correct US Holidays. My only issue is subtracting the holidays from my dates or add another day to my dates.

    Friday, April 5, 2019 4:29 PM
  • User475983607 posted

    My only issue is subtracting the holidays from my dates or add another day to my dates.

    I don't understand why there is a problem.  If you have the holidays in a table already then just query the table.  The query results are the dates that are either excluded or added.  How you determine when to exclude or when to add is not clear.

    Friday, April 5, 2019 4:53 PM
  • User457850011 posted

    I am not using a database table. The code that I provided is doing that. I have made modification to the code.

    private static bool IsHoliday(DateTime value, List<DateTime> holidays = null)
    {
    var currentYearholiday = DateTime.Now.Year;
    if (null == holidays)
    holidays = new List<DateTime>(GetHolidays(currentYearholiday));

    return (value.DayOfWeek == DayOfWeek.Sunday) ||
    (value.DayOfWeek == DayOfWeek.Saturday) ||
    holidays.Any(holiday => holiday.Day == value.Day &&
    holiday.Month == value.Month);
    }

    public static int BusinessDays(DateTime fromDate, DateTime toDate, List<DateTime> holidays)
    {
    var result = 0;
    for (var date = fromDate;
    date < toDate.Date;
    date = date.AddDays(1))
    if (!IsHoliday(date, holidays))
    result += 1;

    return result;
    }


    static void Main(string[] args)
    {


    var StartDate = DateTime.Parse("06/27/2019");
    var SeriesEndDate = DateTime.Parse("07/30/2019");

    var currentyear = DateTime.Now.Year;
    var GH = GetHolidays(currentyear);
    var firstMonday = Enumerable.Range(0, 7)
    .Select(x => StartDate.AddDays(x))
    .First();
    var ts = (SeriesEndDate - StartDate);

    var dates = new List<BusinessWeekDays>();

    for (var i = 0; i < ts.Days; i += 7)
    {
    if (BusinessDays(StartDate, SeriesEndDate, new List<DateTime>(GetHolidays(currentyear))) != 0)
    {
    dates.Add(new BusinessWeekDays
    {Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 7)});
    }
    }

    Console.WriteLine(dates);
    }
    }
    }

    As you can see  bool IsHoliday check if is a holiday exactly like sql query.  And BusinessDays get the Business days

    Friday, April 5, 2019 5:10 PM
  • User475983607 posted

    If you have the holidays, regardless if the dates originated from a table or not, then you have all the dates that are either excluded or added.  The reason why a date is excluded or added is not clear but you have the dates you can do whatever processing you like.  

    Friday, April 5, 2019 5:25 PM
  • User457850011 posted

    I agree but this portion doesn't seems to do what I want

    for (var i = 0; i < ts.Days; i += 7)
    {
    if (BusinessDays(StartDate, SeriesEndDate, new List<DateTime>(GetHolidays(currentyear))) != 0)
    {
    dates.Add(new BusinessWeekDays
    {Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 7)});
    }
    }

    Friday, April 5, 2019 5:34 PM
  • User475983607 posted

    I agree but this portion doesn't seems to do what I want

    for (var i = 0; i < ts.Days; i += 7)
    {
    if (BusinessDays(StartDate, SeriesEndDate, new List<DateTime>(GetHolidays(currentyear))) != 0)
    {
    dates.Add(new BusinessWeekDays
    {Monday = firstMonday.AddDays(i), Sunday = firstMonday.AddDays(i + 7)});
    }
    }

    You have not explained what you want and I do not understand the code.

    Here is a basic example of removing a holiday.

            static void Main(string[] args)
            {
    
                List<DateTime> holidays = new List<DateTime>() { new DateTime(2019, 7, 4) };
    
    
                var StartDate = DateTime.Parse("06/27/2019");
                var SeriesEndDate = DateTime.Parse("07/30/2019");
    
                List<DateTime> results = Enumerable.Range(0, 1 + SeriesEndDate.Subtract(StartDate).Days)
                    .Select(offset => StartDate.AddDays(offset))
                    .ToList();
    
                foreach(var item in holidays)
                {
                    results.Remove(item);
                }
    
                foreach(var result in results)
                {
                    Console.WriteLine(result);
                }
    
            }

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Friday, April 5, 2019 6:08 PM
  • User457850011 posted

    Thanks I will give a try. I will mark it as answer for now

    Friday, April 5, 2019 6:26 PM