Chris's coding blog

A C# UK bank holiday calculator

May 21, 2014

In the UK we’re fortunate enough to get 5 free holidays a year, under the guise of “Bank Holidays”. These are mostly on Mondays and come in January, March/April, May, August and December.

Below is a calculator for working out the dates of these holidays, along with tests for the next 5 years. The class tells you if you’re on a bank holiday, but could be easily changed to return the bank holiday dates. For now, it doesn’t tell you if you’re on the Boxing Day bank holiday.

public class BankHolidayCalculator
{
public bool IsJanuaryBankHolidayMonday(DateTime currentDateTime)
{
// January bank holiday falls on the first working day after New Year's day,
// which is usually January 1st itself.
DateTime newYearsDay = new DateTime(currentDateTime.Year, 01, 01);
DateTime bankHoliday = newYearsDay;
while (IsWorkingDay(bankHoliday.DayOfWeek) == false)
{
bankHoliday = bankHoliday.AddDays(1);
}
return currentDateTime.Date == bankHoliday.Date;
}
public bool IsEasterBankHolidayMonday(DateTime currentDateTime)
{
// Easter bank holiday is always the Monday after Easter Sunday.
DateTime easterSunday = GetEasterSunday(currentDateTime.Year);
return easterSunday.AddDays(1).Date == currentDateTime.Date;
}
public DateTime GetEasterSunday(int year)
{
// From http://stackoverflow.com/a/2510411/21574
int day = 0;
int month = 0;
int g = year % 19;
int c = year / 100;
int h = (c - (int)(c / 4) - (int)((8 * c + 13) / 25) + 19 * g + 15) % 30;
int i = h - (int)(h / 28) * (1 - (int)(h / 28) * (int)(29 / (h + 1)) * (int)((21 - g) / 11));
day = i - ((year + (int)(year / 4) + i + 2 - c + (int)(c / 4)) % 7) + 28;
month = 3;
if (day > 31)
{
month++;
day -= 31;
}
return new DateTime(year, month, day);
}
public bool IsMayBankHolidayMonday(DateTime currentDateTime)
{
// The first Monday of May is a bank holiday (May day)
DateTime firstMayBankHoliday = new DateTime(currentDateTime.Year, 05, 01);
while (firstMayBankHoliday.DayOfWeek != DayOfWeek.Monday)
{
firstMayBankHoliday = firstMayBankHoliday.AddDays(1);
}
if (currentDateTime.Date == firstMayBankHoliday.Date)
return true;
// The last Monday of May is a bank holiday (Spring bank holiday)
DateTime lastMayBankHoliday = new DateTime(currentDateTime.Year, 05, 31);
while (lastMayBankHoliday.DayOfWeek != DayOfWeek.Monday)
{
lastMayBankHoliday = lastMayBankHoliday.AddDays(-1);
}
if (currentDateTime.Date == lastMayBankHoliday.Date)
return true;
return false;
}
public bool IsAugustBankHolidayMonday(DateTime currentDateTime)
{
// The last Monday of August is a bank holiday
DateTime augustBankHoliday = new DateTime(currentDateTime.Year, 08, 31);
while (augustBankHoliday.DayOfWeek != DayOfWeek.Monday)
{
augustBankHoliday = augustBankHoliday.AddDays(-1);
}
if (currentDateTime.Date == augustBankHoliday.Date)
return true;
else
return false;
}
public bool IsDecemberBankHoliday(DateTime currentDateTime)
{
// December's bank holiday is the first working day on, or after Boxing day.
DateTime boxingDay = new DateTime(currentDateTime.Year, 12, 26);
DateTime bankHoliday = boxingDay;
if (boxingDay.DayOfWeek == DayOfWeek.Monday)
bankHoliday = boxingDay.AddDays(1);
while (IsWorkingDay(bankHoliday.DayOfWeek) == false)
{
bankHoliday = bankHoliday.AddDays(1);
}
if (currentDateTime.Date == bankHoliday.Date)
return true;
else
return false;
}
public bool IsWorkingDay(DayOfWeek dayOfWeek)
{
if (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)
return false;
return true;
}
}

using System;
using NUnit.Framework;
[TestFixture]
public class BankHolidayCalculatorTests
{
[Test]
[TestCase("Jan 1 2015")]
[TestCase("Jan 1 2016")]
[TestCase("Jan 2 2017")]
[TestCase("Jan 1 2018")]
[TestCase("Jan 1 2019")]
[TestCase("Jan 1 2020")]
public void should_be_january_bank_holiday(string date)
{
// Arrange
DateTime dateTime = DateTime.Parse(date);
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsJanuaryBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.True);
}
[Test]
public void should_not_be_january_bank_holiday()
{
// Arrange
DateTime dateTime = DateTime.Parse("Jan 1 2017");
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.False);
}
[Test]
[TestCase("May 4 2015")]
[TestCase("May 25 2015")]
[TestCase("May 2 2016")]
[TestCase("May 30 2016")]
[TestCase("May 1 2017")]
[TestCase("May 29 2017")]
public void should_be_may_bank_holiday(string date)
{
// Arrange
DateTime dateTime = DateTime.Parse(date);
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.True);
}
[Test]
public void should_not_be_may_bank_holiday()
{
// Arrange
DateTime dateTime = DateTime.Parse("May 9 2017");
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.False);
}
[Test]
[TestCase("August 31 2015")]
[TestCase("August 29 2016")]
[TestCase("August 28 2017")]
[TestCase("August 27 2018")]
public void should_be_august_bank_holiday(string date)
{
// Arrange
DateTime dateTime = DateTime.Parse(date);
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsAugustBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.True);
}
[Test]
public void should_not_be_august_bank_holiday()
{
// Arrange
DateTime dateTime = DateTime.Parse("August 14 2017");
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.False);
}
[Test]
[TestCase("6 April 2015")]
[TestCase("28 March 2016")]
[TestCase("17 April 2017")]
[TestCase("2 April 2018")]
[TestCase("22 April 2019")]
[TestCase("13 April 2020")]
public void should_be_easter_bank_holiday(string date)
{
// Arrange
DateTime dateTime = DateTime.Parse(date);
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsEasterBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.True);
}
[Test]
public void should_not_be_easter_bank_holiday()
{
// Arrange
DateTime dateTime = DateTime.Parse("April 13 2015");
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.False);
}
[Test]
[TestCase("26 December 2014")]
[TestCase("28 December 2015")]
[TestCase("27 December 2016")]
[TestCase("26 December 2017")]
[TestCase("26 December 2018")]
[TestCase("26 December 2019")]
[TestCase("26 December 2019")]
[TestCase("28 December 2020")]
public void should_be_december_bank_holiday(string date)
{
// Arrange
DateTime dateTime = DateTime.Parse(date);
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsDecemberBankHoliday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.True);
}
[Test]
public void should_not_be_december_bank_holiday()
{
// Arrange
DateTime dateTime = DateTime.Parse("29 December 2014");
BankHolidayCalculator calculator = new BankHolidayCalculator();
// Act
bool isBankHoliday = calculator.IsMayBankHolidayMonday(dateTime);
// Assert
Assert.That(isBankHoliday, Is.False);
}
}

csharp

Chris Small

I'm Chris Small, a software engineer living and working in London. This is my tech blog. Find out more via GithubStackoverflowResume