DateTime extensions for holyday and businessday calculations

Extension methods are a very powerful feature of .Net. Here is an example of DateTime extensions to determine the holydays of a certain year. It also provides an algorithm to add workingdays to a DateTime object. The Easter calculation method was found here.

public static class DateTimeExtensions
{
	/// <summary>
	/// Telt werkbare dagen op bij een <see cref="DateTime"/>.
	/// </summary>
	/// <param name="date">De datum.</param>
	/// <param name="days">Het aantal werkdagen.</param>
	/// <param name="extraHolidays">De extra niet werkbare dagen.</param>
	/// <returns>Een <see cref="DateTime"/> waarvan de waarde een som is van de opgegeven datum en het aantal werkbare dagen.</returns>
	/// <remarks>
	/// Standaard wordt al rekening gehouden met Nieuwjaarsdag, Pasen, Hemelvaart, Pinksteren en Kerst
	/// (<seealso cref="DateTimeExtensions.Holydays"/>). Andere niet werkbare dagen, zoals Koninginnedag en
	/// Bevrijdingsdag, kunnen hier opgegeven worden.
	/// </remarks>
	public static DateTime AddBusinessDays(this DateTime date, int days, IEnumerable<DateTime> extraHolidays = null)
	{
		int year = date.Year;
		IEnumerable<DateTime> holydays = extraHolidays == null ? Holydays(year) : Holydays(year).Union(extraHolidays);

		int direction = days < 0 ? -1 : 1;

		date = date.Date;
		while (days != 0)
		{
			date = date.AddDays(direction);
			if (year != date.Year)
			{
				year = date.Year;
				holydays = extraHolidays == null ? Holydays(year) : Holydays(year).Union(extraHolidays);
			}

			if (date.IsWeekend() == false && holydays.Contains(date) == false)
				days -= direction;
		}

		return date;
	}

	public static bool IsWeekend(this DateTime datetime)
	{
		return datetime.DayOfWeek == DayOfWeek.Saturday || datetime.DayOfWeek == DayOfWeek.Sunday;
	}

	public static bool IsNewYearsDay(this DateTime datetime)
	{
		return datetime.Date == NewYearsDay(datetime.Year);
	}

	// Eerste Paasdag (zondag)
	public static bool IsEaster(this DateTime datetime)
	{
		return datetime.Date == Easter(datetime.Year);
	}

	// Tweede Paasdag (maandag)
	public static bool IsEasterMonday(this DateTime datetime)
	{
		return datetime.Date == EasterMonday(datetime.Year);
	}

	// Hemelvaartsdag (donderdag)
	public static bool IsAscensionDay(this DateTime datetime)
	{
		return datetime.Date == AscensionDay(datetime.Year);
	}

	// Eerste Pinksterdag
	public static bool IsWhitSunday(this DateTime datetime)
	{
		return datetime.Date == WhitSunday(datetime.Year);
	}

	// Tweede Pinksterdag
	public static bool IsWhitMonday(this DateTime datetime)
	{
		return datetime.Date == WhitMonday(datetime.Year);
	}

	// Eerste Kerstdag
	public static bool IsChristmasDay(this DateTime datetime)
	{
		return datetime.Date == ChristmasDay(datetime.Year);
	}

	// Tweede Kerstdag
	public static bool IsBoxingDay(this DateTime datetime)
	{
		return datetime.Date == BoxingDay(datetime.Year);
	}

	public static DateTime NewYearsDay(int year)
	{
		return new DateTime(year, 1, 1);
	}

	public static DateTime Easter(int year)
	{
		// Gauss Calculation
		int month = 3;

		// Determine the Golden number:
		int goldenNumber = year % 19 + 1;

		// Determine the century number:
		int century = year / 100 + 1;

		// Correct for the years who are not leap years:
		int leapYearCorrection = (3 * century) / 4 - 12;

		// Mooncorrection:
		int moonCorrection = (8 * century + 5) / 25 - 5;

		// Find sunday:
		int sunday = (5 * year) / 4 - leapYearCorrection - 10;

		// Determine epact (age of moon on 1 januari of that year (follows a cycle of 19 years):
		int epact = (11 * goldenNumber + 20 + moonCorrection - leapYearCorrection) % 30;

		if (epact == 24) epact++;
		if ((epact == 25) && (goldenNumber > 11)) epact++;

		// Get the full moon:
		int fullMoon = 44 - epact;
		if (fullMoon < 21) { fullMoon = fullMoon + 30; }

		// Up to sunday:
		int day = (fullMoon + 7) - ((sunday + fullMoon) % 7);

		// Easterdate:
		if ( day > 31 )
		{
			day = day - 31;
			month = 4;
		}

		return new DateTime(year, month, day);
	}

	public static DateTime EasterMonday(int year)
	{
		return Easter(year).AddDays(1);
	}

	public static DateTime AscensionDay(int year)
	{
		return Easter(year).AddDays(39);
	}

	public static DateTime WhitSunday(int year)
	{
		return Easter(year).AddDays(49);
	}

	public static DateTime WhitMonday(int year)
	{
		return Easter(year).AddDays(50);
	}

	public static DateTime ChristmasDay(int year)
	{
		return new DateTime(year, 12, 25);
	}

	public static DateTime BoxingDay(int year)
	{
		return ChristmasDay(year).AddDays(1);
	}

	public static IEnumerable<DateTime> Holydays(int year)
	{
		return new DateTime[] {
			NewYearsDay(year),
			Easter(year),
			EasterMonday(year),
			AscensionDay(year),
			WhitSunday(year),
			WhitMonday(year),
			ChristmasDay(year),
			BoxingDay(year)
		};
	}
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: