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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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