Skip to content

Instantly share code, notes, and snippets.

@frne
Created January 26, 2023 11:15
Show Gist options
  • Save frne/d14e7e0eb67414d5dae48d9f231cf54c to your computer and use it in GitHub Desktop.
Save frne/d14e7e0eb67414d5dae48d9f231cf54c to your computer and use it in GitHub Desktop.
Example implementation of Swiss Bank Holidays in Kotlin
import BankHoliday.Companion.isBankHoliday
import java.time.LocalDate
import java.time.Year
fun main(args: Array<String>) {
// some tests (should be done using JUnit of course ;)
mapOf(
LocalDate.of(2023, 1, 1) to true,
LocalDate.of(2023, 8, 1) to true,
LocalDate.of(2023, 12, 25) to true,
LocalDate.of(2023, 12, 26) to true,
LocalDate.of(2023, 4, 9) to true,
LocalDate.of(2023, 4, 7) to true,
LocalDate.of(2023, 9, 5) to false,
LocalDate.of(2023, 1, 2) to false
).forEach { (date, assumption) ->
val res = if (date.isBankHoliday() == assumption) "✓" else "×"
println("Asserting that $date isBankHoliday should be $assumption: $res")
}
}
// Sealed supertype which can only be implemented from the same file / package
sealed class BankHoliday(
val date: LocalDate
) {
companion object {
private fun holidays(year: Year) = listOf(
Easter(year),
AscensionDay(year),
EasterMonday(year),
GoodFriday(year),
WhitMonday(year),
BoxingDay(year),
ChristmasDay(year),
FirstOfJanuary(year),
NationalDay(year)
)
fun LocalDate.isBankHoliday(): Boolean =
holidays(Year.of(this.year)).any { h ->
this.compareTo(h.date) == 0
}
}
}
class Easter(year: Year) : BankHoliday(calculate(year)) {
companion object {
private fun calculate(year: Year): LocalDate {
val y = year.value
val n = y % 19
val c = y / 100
val u = y % 100
val s = c / 4
val t = c % 4
val p = (c + 8) / 25
val q = (c - p + 1) / 3
val e = (19 * n + c - s - q + 15) % 30
val b = u / 4
val d = u % 4
val L = (2 * t + 2 * b - e - d + 32) % 7
val h = (n + 11 * e + 22 * L) / 451
val calculatedMonth = (e + L - 7 * h + 114) / 31
val calculatedDay = (e + L - 7 * h + 114) % 31 + 1
return LocalDate.of(y, calculatedMonth, calculatedDay)
}
}
}
// Complex dates based on easter
class AscensionDay(year: Year) : BankHoliday(
Easter(year)
.date
.plusDays(39)
)
class EasterMonday(year: Year) : BankHoliday(
Easter(year)
.date
.plusDays(1)
)
class GoodFriday(year: Year) : BankHoliday(
Easter(year)
.date
.minusDays(2)
)
class WhitMonday(year: Year) : BankHoliday(
Easter(year)
.date
.plusDays(50)
)
// Simple dates
class BoxingDay(year: Year) : BankHoliday(
year.atMonth(12).atDay(26)
)
class ChristmasDay(year: Year) : BankHoliday(
year.atMonth(12).atDay(25)
)
class FirstOfJanuary(year: Year) : BankHoliday(
year.atMonth(1).atDay(1)
)
class NationalDay(year: Year) : BankHoliday(
year.atMonth(8).atDay(1)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment