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); | |
} | |
} |
I'm Chris Small, a software engineer working in London. This is my tech blog. Find out more about me via Github, Stackoverflow, Resume