namespace WorkingDayCalculator.Core.Enums
{
public enum Ordinal
{
// The library uses these values in mathematical calculations. The values
// that are set are important and should not be changed unless the developer
// is going to modify the math calculations which rely on these values.
Last = -1,
First = 0,
Second = 1,
Third = 2,
Fourth = 3,
Fifth = 4,
}
}
using System;
using WorkingDayCalculator.Core.Enums;
namespace WorkingDayCalculator.Core
{
public static class DateHelper
{
public static DateTime GetOrdinalDate(int year, Month month, Ordinal ordinal, DayOfWeek dayOfWeek)
{
DateTime ordinalDate;
if (ordinal == Ordinal.Last)
{
DateTime startDate = (new DateTime(year, (int)month + 1, 1)).AddDays(-1);
int offsetFromDayOfWeek = GetPastOffsetFromTarget(startDate.DayOfWeek, dayOfWeek);
ordinalDate = startDate.AddDays(-1 * offsetFromDayOfWeek);
}
else
{
DateTime startDate = new DateTime(year, (int)month, 1);
int offsetFromDayOfWeek = GetFutureOffsetFromTarget(startDate.DayOfWeek, dayOfWeek);
int weeksToAdd = (int)ordinal * 7;
ordinalDate = startDate.AddDays(offsetFromDayOfWeek + weeksToAdd);
if (ordinalDate.Month != (int)month)
{
throw new ArgumentException("Not enough days in month to satisfy ordinal requirement.");
}
}
return ordinalDate;
}
public static int GetFutureOffsetFromTarget(DayOfWeek day, DayOfWeek target)
{
return ((int)(DayOfWeek.Saturday - day) + (int)target + 1) % 7;
}
public static int GetPastOffsetFromTarget(DayOfWeek day, DayOfWeek target)
{
return ((int)day + (int)DayOfWeek.Saturday - (int)target + 1) % 7;
}
}
}
public static DateTime GetNewYearsDay(int year, HolidayOptions options = null)
{
DateTime holiday = new DateTime(year, (int)Holiday.NewYearsDayMonth, 1);
holiday = AdjustIfObserved(holiday, options, Holidays.NewYearsDay);
return holiday;
}
public static DateTime GetLaborDay(int year, HolidayOptions options = null)
{
DateTime holiday = DateHelper.GetOrdinalDate(year, Holiday.LaborDayMonth, Ordinal.First, DayOfWeek.Monday);
holiday = AdjustIfObserved(holiday, options, Holidays.LaborDay);
return holiday;
}
public static bool IsNewYearsDay(DateTime date, HolidayOptions options = null)
{
DateTime holiday = GetNewYearsDay(date.Year, options);
return (holiday == date.Date);
}
public static bool IsHoliday(DateTime date, HolidayOptions options = null)
{
HolidayOptions safeOptions = options ?? new HolidayOptions();
Holidays holidaysToCheck = safeOptions.HolidaysToCheck;
// Month check saves us a call to the function if we know that we're not in
// the correct month anyway.
// It's possible that we may have holidays that are checked for more frequently.
// We could rearrange these in order of precedence/frequency, but that's probably
// a micro-optimization if anything.
return (date.Month == (int)Holiday.ChristmasDayMonth && holidaysToCheck.HasFlag(Holidays.ChristmasDay) && IsChristmasDay(date, safeOptions)) ||
(date.Month == (int)Holiday.ColumbusDayMonth && holidaysToCheck.HasFlag(Holidays.ColumbusDay) && IsColumbusDay(date, safeOptions)) ||
(date.Month == (int)Holiday.IndependenceDayMonth && holidaysToCheck.HasFlag(Holidays.IndependenceDay) && IsIndependenceDay(date, safeOptions)) ||
(date.Month == (int)Holiday.LaborDayMonth && holidaysToCheck.HasFlag(Holidays.LaborDay) && IsLaborDay(date, safeOptions)) ||
(date.Month == (int)Holiday.MartinLutherKingDayMonth && holidaysToCheck.HasFlag(Holidays.MartinLutherKingDay) && IsMartinLutherKingDay(date, safeOptions)) ||
(date.Month == (int)Holiday.MemorialDayMonth && holidaysToCheck.HasFlag(Holidays.MemorialDay) && IsMemorialDay(date, safeOptions)) ||
(date.Month == (int)Holiday.NewYearsDayMonth && holidaysToCheck.HasFlag(Holidays.NewYearsDay) && IsNewYearsDay(date, safeOptions)) ||
(date.Month == (int)Holiday.PresidentsDayMonth && holidaysToCheck.HasFlag(Holidays.PresidentsDay) && IsPresidentsDay(date, safeOptions)) ||
(date.Month == (int)Holiday.ThanksgivingDayMonth && holidaysToCheck.HasFlag(Holidays.ThanksgivingDay) && IsThanksgivingDay(date, safeOptions)) ||
(date.Month == (int)Holiday.VeteransDayMonth && holidaysToCheck.HasFlag(Holidays.VeteransDay) && IsVeteransDay(date, safeOptions));
}
using System;
namespace WorkingDayCalculator.Core
{
public static class WorkingDay
{
public static DateTime GetNextWorkingDay(DateTime date, HolidayOptions options = null)
{
return GetNextWorkingDay(date, Holiday.IsHoliday, options);
}
public static DateTime GetNextWorkingDay(DateTime date, Func<DateTime, HolidayOptions, bool> holidayCalculator, HolidayOptions options = null)
{
DateTime workingDay = GetWorkingDayUsingOffset(date, 1, holidayCalculator, options);
return workingDay;
}
public static DateTime GetPreviousWorkingDay(DateTime date, HolidayOptions options = null)
{
return GetPreviousWorkingDay(date, Holiday.IsHoliday, options);
}
public static DateTime GetPreviousWorkingDay(DateTime date, Func<DateTime, HolidayOptions, bool> holidayCalculator, HolidayOptions options = null)
{
DateTime workingDay = GetWorkingDayUsingOffset(date, -1, holidayCalculator, options);
return workingDay;
}
private static DateTime GetWorkingDayUsingOffset(DateTime date, int offset, Func<DateTime, HolidayOptions, bool> holidayCalculator, HolidayOptions options = null)
{
DateTime workingDay = date.AddDays(offset);
while (workingDay.DayOfWeek == DayOfWeek.Saturday || workingDay.DayOfWeek == DayOfWeek.Sunday || holidayCalculator(workingDay, options))
{
workingDay = workingDay.AddDays(offset);
}
return workingDay;
}
}
}
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (2)
Commented:
Commented:
https://www.experts-exchange.com/articles/201/Handling-Date-and-Time-in-PHP-and-MySQL-Procedural-Version.html
https://www.experts-exchange.com/articles/20920/Handling-Time-and-Date-in-PHP-and-MySQL-OOP-Version.html