diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Revision history for holidays
+
+## **0.1.0.0** - 2025-02-04
+- small EDSL for describing holidays
+- ZAF, NAM, USA, GBR, DEU
+- support for country regions
+- unit + property based tests
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Daniel Cabral
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/holidays.cabal b/holidays.cabal
new file mode 100644
--- /dev/null
+++ b/holidays.cabal
@@ -0,0 +1,63 @@
+cabal-version: 3.8
+
+name: holidays
+version: 0.1.0.0
+synopsis: Library for country public holidays
+description:
+  Library for country public holidays. Provides a small EDSL to describe holidays for a country.
+category: Date
+homepage: https://github.com/danielc777888/holidays
+license: MIT
+license-file: LICENSE
+author: Daniel Cabral
+maintainer: danielc777888@gmail.com
+extra-doc-files: CHANGELOG.md
+
+tested-with: GHC == 9.4.8
+
+source-repository head
+  type: git
+  location: git://github.com/danielc777888/holidays.git
+
+common common
+  ghc-options: -Wall
+  build-depends:
+    base ^>=4.17.2.1,
+    containers ^>=0.7,
+    text ^>=2.1,
+    time >=1.4 && <2
+  default-language: GHC2021
+
+library
+  import: common
+  exposed-modules:
+    Holidays
+  other-modules:
+    Holidays.Base
+    Holidays.DateFinder
+    Holidays.DateTransform
+    Holidays.Germany
+    Holidays.Namibia
+    Holidays.SouthAfrica
+    Holidays.UnitedKingdom
+    Holidays.UnitedStates
+  hs-source-dirs: src
+
+test-suite tests
+  import: common
+  type: exitcode-stdio-1.0
+  build-depends:
+    holidays,
+    tasty >=1.5,
+    tasty-hunit >=0.10,
+    tasty-quickcheck >=0.10,
+    text ^>=2.1
+  hs-source-dirs: tst
+  main-is: Main.hs
+  other-modules:
+    Test.Holidays
+    Test.Holidays.Germany
+    Test.Holidays.Namibia
+    Test.Holidays.SouthAfrica
+    Test.Holidays.UnitedKingdom
+    Test.Holidays.UnitedStates
diff --git a/src/Holidays.hs b/src/Holidays.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+{- |
+This module determines public holidays based on country code and year.
+-}
+module Holidays (
+  ISO_3166_1_Alpha_3,
+  Region,
+  holidays,
+)
+where
+
+import Data.Set qualified as S
+import Data.Time
+import Holidays.Base
+import Holidays.DateFinder
+import Holidays.DateTransform
+import Holidays.Germany qualified as DEU
+import Holidays.Namibia qualified as NAM
+import Holidays.SouthAfrica qualified as ZAF
+import Holidays.UnitedKingdom qualified as GBR
+import Holidays.UnitedStates qualified as USA
+
+{- |
+Returns a set of public holidays based on the country code (ISO_3166_1_Alpha_3) and a specific year.
+If a country is not supported an empty set is returned.
+Allowed to specify regions in a country to further determine holidays.
+
+Examples:
+
+@
+holidays "DEU" ["BW","BY","BE"] 2025 -- Germany and various states
+holidays "USA" [] 2025
+@
+-}
+holidays :: ISO_3166_1_Alpha_3 -> [Region] -> Year -> S.Set Day
+holidays countryCode regions year =
+  case countryCode of
+    "DEU" -> DEU.holidays regions `apply` year
+    "GBR" -> GBR.holidays `apply` year
+    "NAM" -> NAM.holidays `apply` year
+    "USA" -> USA.holidays `apply` year
+    "ZAF" -> ZAF.holidays `apply` year
+    _ -> S.empty
+
+-- Applies year and transformations to holidays
+apply :: (DateFinders, DateTransforms) -> Year -> S.Set Day
+apply (finders, transforms) year =
+  let validDays = filter valid $ map (\d -> d year) finders -- apply year and filter out invalid days
+  in  foldr (\d ds -> S.insert (foldr (\t d' -> t ds d') d transforms) ds) S.empty validDays -- apply transforms to valid days
diff --git a/src/Holidays/Base.hs b/src/Holidays/Base.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/Base.hs
@@ -0,0 +1,17 @@
+module Holidays.Base (
+  ISO_3166_1_Alpha_3,
+  Region,
+  day,
+) where
+
+import Data.Text qualified as T
+import Data.Time
+
+-- | 3-letter country codes
+type ISO_3166_1_Alpha_3 = T.Text
+
+-- | Custom regions for a country
+type Region = T.Text
+
+day :: Year -> MonthOfYear -> DayOfMonth -> Day
+day = fromGregorian
diff --git a/src/Holidays/DateFinder.hs b/src/Holidays/DateFinder.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/DateFinder.hs
@@ -0,0 +1,174 @@
+module Holidays.DateFinder (
+  after,
+  before,
+  valid,
+  days,
+  years,
+  sun,
+  mon,
+  tues,
+  wed,
+  thurs,
+  fri,
+  sat,
+  jan,
+  feb,
+  mar,
+  apr,
+  may,
+  jun,
+  jul,
+  aug,
+  sep,
+  oct,
+  nov,
+  dec,
+  easterSunday,
+  easterMonday,
+  goodFriday,
+  christmasDay,
+  boxingDay,
+  newYearsDay,
+  ascensionDay,
+  workersDay,
+  nextOpenDay,
+  DateFinders,
+) where
+
+import Data.Maybe
+import Data.Set qualified as S
+import Data.Time
+
+import Data.Time.Calendar.Easter
+import Holidays.Base
+
+data Direction = Past | Future
+
+type DateFinders = [Year -> Day]
+
+-- common dates
+newYearsDay :: Year -> Day
+newYearsDay = jan 1
+
+easterSunday :: Year -> Day
+easterSunday = gregorianEaster
+
+easterMonday :: Year -> Day
+easterMonday = addDays 1 . easterSunday
+
+goodFriday :: Year -> Day
+goodFriday = (1 `fri`) . before . easterSunday
+
+christmasDay :: Year -> Day
+christmasDay = dec 25
+
+boxingDay :: Year -> Day
+boxingDay = dec 26
+
+ascensionDay :: Year -> Day
+ascensionDay = (39 `days`) . after . easterSunday
+
+workersDay :: Year -> Day
+workersDay = may 1
+
+-- utils
+nullDate :: Day
+nullDate = day 0 0 0
+
+valid :: Day -> Bool
+valid = not . (nullDate ==)
+
+days :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+days n f = f n Nothing
+
+years :: (Year -> Bool) -> Day -> Day
+years f d = if f (fromIntegral y) then d else nullDate
+  where
+    (y, _, _) = toGregorian d
+
+-- months
+jan :: DayOfMonth -> Year -> Day
+jan d y = day y January d
+
+feb :: DayOfMonth -> Year -> Day
+feb d y = day y February d
+
+mar :: DayOfMonth -> Year -> Day
+mar d y = day y March d
+
+apr :: DayOfMonth -> Year -> Day
+apr d y = day y April d
+
+may :: DayOfMonth -> Year -> Day
+may d y = day y May d
+
+jun :: DayOfMonth -> Year -> Day
+jun d y = day y June d
+
+jul :: DayOfMonth -> Year -> Day
+jul d y = day y July d
+
+aug :: DayOfMonth -> Year -> Day
+aug d y = day y August d
+
+sep :: DayOfMonth -> Year -> Day
+sep d y = day y September d
+
+oct :: DayOfMonth -> Year -> Day
+oct d y = day y October d
+
+nov :: DayOfMonth -> Year -> Day
+nov d y = day y November d
+
+dec :: DayOfMonth -> Year -> Day
+dec d y = day y December d
+
+-- time travel
+
+-- exclusive of before day
+before :: Day -> Integer -> Maybe DayOfWeek -> Day
+before = timeTravel Past
+
+-- inclusive of after day
+after :: Day -> Integer -> Maybe DayOfWeek -> Day
+after = timeTravel Future
+
+timeTravel :: Direction -> Day -> Integer -> Maybe DayOfWeek -> Day
+timeTravel Past d n w
+  | isNothing w = addDays (negate n) d
+  | otherwise =
+      let diff = fromIntegral $ if dayOfWeek d == fromJust w then 7 else dayOfWeekDiff (dayOfWeek d) (fromJust w)
+      in  addDays (negate diff - ((n - 1) * 7)) d
+timeTravel Future d n w
+  | isNothing w = addDays n d
+  | otherwise =
+      let diff = fromIntegral $ dayOfWeekDiff (fromJust w) (dayOfWeek d)
+      in  addDays (diff + ((n - 1) * 7)) d
+
+-- week days
+sun :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+sun n f = f n (Just Sunday)
+
+mon :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+mon n f = f n (Just Monday)
+
+tues :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+tues n f = f n (Just Tuesday)
+
+wed :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+wed n f = f n (Just Wednesday)
+
+thurs :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+thurs n f = f n (Just Thursday)
+
+fri :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+fri n f = f n (Just Friday)
+
+sat :: Integer -> (Integer -> Maybe DayOfWeek -> Day) -> Day
+sat n f = f n (Just Saturday)
+
+nextOpenDay :: [DayOfWeek] -> S.Set Day -> Day -> Day
+nextOpenDay ds s d
+  | dayOfWeek d `elem` ds = nextOpenDay ds s (addDays 1 d)
+  | S.member d s = nextOpenDay ds s (addDays 1 d)
+  | otherwise = d
diff --git a/src/Holidays/DateTransform.hs b/src/Holidays/DateTransform.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/DateTransform.hs
@@ -0,0 +1,19 @@
+module Holidays.DateTransform (
+  substituteRule,
+  sundayRule,
+  DateTransforms
+) where
+
+import Data.Set qualified as S
+import Data.Time
+import Holidays.DateFinder
+
+
+type DateTransforms = [S.Set Day -> Day -> Day]
+
+-- general transformations
+sundayRule :: S.Set Day -> Day -> Day
+sundayRule _ d = if dayOfWeek d == Sunday then addDays 1 d else d -- mon after sunday
+
+substituteRule :: S.Set Day -> Day -> Day
+substituteRule = nextOpenDay [Saturday, Sunday]
diff --git a/src/Holidays/Germany.hs b/src/Holidays/Germany.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/Germany.hs
@@ -0,0 +1,153 @@
+{--
+  references:
+  https://en.wikipedia.org/wiki/Public_holidays_in_Germany
+  https://publicholidays.de/
+--}
+{-# LANGUAGE OverloadedStrings #-}
+
+module Holidays.Germany (
+  holidays,
+) where
+
+import Holidays.Base
+import Holidays.DateFinder
+import Holidays.DateTransform
+
+holidays :: [Region] -> (DateFinders, DateTransforms)
+holidays regions =
+  ( concat
+      [ federalHolidays,
+        regionalHolidays regions
+      ],
+    []
+  )
+
+federalHolidays :: DateFinders
+federalHolidays =
+  [ newYearsDay,
+    goodFriday,
+    easterMonday,
+    workersDay, -- labour day
+    ascensionDay,
+    (50 `days`) . after . easterSunday, -- whit monday
+    oct 3, -- germany unity day
+    christmasDay,
+    boxingDay -- second day of christmas
+  ]
+
+regionalHolidays :: [Region] -> DateFinders
+regionalHolidays =
+  concatMap
+    ( \r -> case r of
+        "BW" -> badenWurttembergHolidays
+        "BY" -> bavariaHolidays
+        "BE" -> berlinHolidays
+        "BB" -> brandenburgHolidays
+        "HB" -> bremenHolidays
+        "HH" -> hamburgHolidays
+        "HE" -> hesseHolidays
+        "MV" -> mecklenburgVorpommernHolidays
+        "NI" -> lowerSaxonyHolidays
+        "NW" -> northRhineWestphaliaHolidays
+        "RP" -> rhinelandPalatinateHolidays
+        "SL" -> saarlandHolidays
+        "SN" -> saxonyHolidays
+        "ST" -> saxonyAnhaltHolidays
+        "SH" -> schleswigHolsteinHolidays
+        "TH" -> thuringiaHolidays
+        _ -> []
+    )
+
+badenWurttembergHolidays :: DateFinders
+badenWurttembergHolidays =
+  [ jan 6, -- epiphany
+    (60 `days`) . after . easterSunday, -- corpus christi
+    nov 1 -- all saints day
+  ]
+
+bavariaHolidays :: DateFinders
+bavariaHolidays =
+  [ jan 6, -- epiphany
+    (60 `days`) . after . easterSunday, -- corpus christi
+    aug 15, -- assumption day
+    nov 1 -- all saints day
+  ]
+
+berlinHolidays :: DateFinders
+berlinHolidays =
+  [ mar 8, -- international womens day
+    nov 1, -- all saints day
+    years (== 2025) . may 8 -- 80th anniversary of the end of world war 2
+  ]
+
+brandenburgHolidays :: DateFinders
+brandenburgHolidays =
+  [ easterSunday,
+    (49 `days`) . after . easterSunday, -- whit sunday
+    oct 31 -- reformation day
+  ]
+
+bremenHolidays :: DateFinders
+bremenHolidays =
+  [ oct 31 -- reformation day
+  ]
+
+hamburgHolidays :: DateFinders
+hamburgHolidays =
+  [ oct 31 -- reformation day
+  ]
+
+hesseHolidays :: DateFinders
+hesseHolidays =
+  [ (60 `days`) . after . easterSunday -- corpus christi
+  ]
+
+mecklenburgVorpommernHolidays :: DateFinders
+mecklenburgVorpommernHolidays =
+  [ mar 8, -- international womens day
+    oct 31 -- reformation day
+  ]
+
+lowerSaxonyHolidays :: DateFinders
+lowerSaxonyHolidays =
+  [ oct 31 -- reformation day
+  ]
+
+northRhineWestphaliaHolidays :: DateFinders
+northRhineWestphaliaHolidays =
+  [ (60 `days`) . after . easterSunday, -- corpus christi
+    nov 1 -- all saints day
+  ]
+
+rhinelandPalatinateHolidays :: DateFinders
+rhinelandPalatinateHolidays =
+  [ (60 `days`) . after . easterSunday, -- corpus christi
+    nov 1 -- all saints day
+  ]
+
+saarlandHolidays :: DateFinders
+saarlandHolidays =
+  [ (60 `days`) . after . easterSunday, -- corpus christi
+    aug 15, -- assumption day
+    nov 1 -- all saints day
+  ]
+
+saxonyHolidays :: DateFinders
+saxonyHolidays =
+  [ (2 `wed`) . before . (4 `sun`) . before . christmasDay -- repentance and prayer day
+  ]
+
+saxonyAnhaltHolidays :: DateFinders
+saxonyAnhaltHolidays =
+  [ jan 6, -- epiphany
+    oct 31 -- reformation day
+  ]
+
+schleswigHolsteinHolidays :: DateFinders
+schleswigHolsteinHolidays =
+  []
+
+thuringiaHolidays :: DateFinders
+thuringiaHolidays =
+  [ sep 20 -- world childrens day
+  ]
diff --git a/src/Holidays/Namibia.hs b/src/Holidays/Namibia.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/Namibia.hs
@@ -0,0 +1,29 @@
+-- references:
+-- https://en.wikipedia.org/wiki/Public_holidays_in_Namibia
+
+module Holidays.Namibia (
+  holidays,
+) where
+
+import Holidays.DateFinder
+import Holidays.DateTransform
+
+-- Namibia public holidays
+holidays :: (DateFinders, DateTransforms)
+holidays =
+  ( [ newYearsDay,
+      mar 21, -- independence day
+      goodFriday,
+      easterSunday,
+      ascensionDay,
+      workersDay,
+      may 4, -- cassinga day
+      may 25, -- africa day
+      aug 26, -- heroes day
+      dec 10, -- human rights day
+      christmasDay,
+      boxingDay, -- family day
+      years (>= 2025) . may 28 -- genocide remembrance day
+    ],
+    [sundayRule]
+  )
diff --git a/src/Holidays/SouthAfrica.hs b/src/Holidays/SouthAfrica.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/SouthAfrica.hs
@@ -0,0 +1,28 @@
+-- references:
+-- https://en.wikipedia.org/wiki/Public_holidays_in_South_Africa
+
+module Holidays.SouthAfrica (
+  holidays,
+) where
+
+import Holidays.DateFinder
+import Holidays.DateTransform
+
+holidays :: (DateFinders, DateTransforms)
+holidays =
+  ( [ newYearsDay,
+      goodFriday,
+      easterSunday, -- family day
+      mar 21, -- human right day
+      apr 27, -- freedom day
+      workersDay,
+      jun 16, -- youth day
+      aug 9, -- womens day
+      sep 24, -- heritage day
+      dec 16, -- day of reconciliation
+      christmasDay,
+      boxingDay, -- day of goodwill
+      years (== 2024) . may 29 -- general elections 2024
+    ],
+    [sundayRule]
+  )
diff --git a/src/Holidays/UnitedKingdom.hs b/src/Holidays/UnitedKingdom.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/UnitedKingdom.hs
@@ -0,0 +1,23 @@
+-- references:
+-- https://en.wikipedia.org/wiki/Public_holidays_in_the_United_Kingdom
+
+module Holidays.UnitedKingdom (
+  holidays,
+) where
+
+import Holidays.DateFinder
+import Holidays.DateTransform
+
+holidays :: (DateFinders, DateTransforms)
+holidays =
+  ( [ newYearsDay,
+      goodFriday,
+      easterSunday,
+      (1 `mon`) . after . may 1, -- early may bank holiday
+      (1 `mon`) . before . jun 1, -- spring bank holiday
+      (1 `mon`) . before . sep 1, -- summer bank holiday
+      christmasDay,
+      boxingDay
+    ],
+    [substituteRule]
+  )
diff --git a/src/Holidays/UnitedStates.hs b/src/Holidays/UnitedStates.hs
new file mode 100644
--- /dev/null
+++ b/src/Holidays/UnitedStates.hs
@@ -0,0 +1,26 @@
+-- references:
+-- https://en.wikipedia.org/wiki/Federal_holidays_in_the_United_States
+
+module Holidays.UnitedStates (
+  holidays,
+) where
+
+import Holidays.DateFinder
+import Holidays.DateTransform
+
+holidays :: (DateFinders, DateTransforms)
+holidays =
+  ( [ newYearsDay,
+      (3 `mon`) . after . jan 1, -- Martin Luther King's birthday
+      (3 `mon`) . after . feb 1, -- Georges Washington's birthday
+      (1 `mon`) . before . jun 1, -- memorial day, last monday of may
+      jun 19, -- juneteenth independence day
+      jul 4, -- independence day
+      (1 `mon`) . after . sep 1, -- labor day
+      (2 `mon`) . after . oct 1, -- columbus day
+      nov 11, -- veterans day,
+      (4 `thurs`) . after . nov 1, -- thanksgiving day
+      christmasDay
+    ],
+    []
+  )
diff --git a/tst/Main.hs b/tst/Main.hs
new file mode 100644
--- /dev/null
+++ b/tst/Main.hs
@@ -0,0 +1,20 @@
+module Main where
+
+import Test.Holidays.Germany qualified as DEU
+import Test.Holidays.Namibia qualified as NAM
+import Test.Holidays.SouthAfrica qualified as ZAF
+import Test.Holidays.UnitedKingdom qualified as GBR
+import Test.Holidays.UnitedStates qualified as USA
+import Test.Tasty
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: TestTree
+tests = testGroup "Holidays tests" [unitTests, propTests]
+
+unitTests :: TestTree
+unitTests = testGroup "Unit tests" [DEU.unitTests, GBR.unitTests, NAM.unitTests, USA.unitTests, ZAF.unitTests]
+
+propTests :: TestTree
+propTests = testGroup "Holidays property based tests" [DEU.propTests, GBR.propTests, NAM.propTests, USA.propTests, ZAF.propTests]
diff --git a/tst/Test/Holidays.hs b/tst/Test/Holidays.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays.hs
@@ -0,0 +1,30 @@
+module Test.Holidays (
+  countryPropTests,
+  day,
+) where
+
+import Data.Set qualified as S
+import Data.Time
+import Holidays qualified as H
+import Test.Tasty
+import Test.Tasty.QuickCheck as QC
+
+day :: Year -> MonthOfYear -> DayOfMonth -> Day
+day = fromGregorian
+
+countryPropTests :: H.ISO_3166_1_Alpha_3 -> [H.Region] -> TestTree
+countryPropTests countryCode regions =
+  let uniqueYears c y =
+        S.map
+          ( \h ->
+              let
+                (year', _, _) = toGregorian h
+              in
+                year'
+          )
+          (H.holidays c regions y)
+  in  testGroup
+        ("Holidays property based tests for country " <> show countryCode)
+        [ QC.testProperty "Day always in the same year" $
+            \year -> S.singleton year == uniqueYears countryCode year
+        ]
diff --git a/tst/Test/Holidays/Germany.hs b/tst/Test/Holidays/Germany.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays/Germany.hs
@@ -0,0 +1,48 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.Holidays.Germany (
+  unitTests,
+  propTests,
+) where
+
+import Data.Set qualified as S
+import Holidays
+import Test.Holidays
+import Test.Tasty
+import Test.Tasty.HUnit
+
+-- german states
+regions :: [Region] 
+regions = ["BW","BY","BE","BB","HB","HH","HE","MV","NI","NW","RP","SL","SN","ST","SH","TH"]
+
+unitTests :: TestTree
+unitTests =
+  testGroup
+    "DEU unit tests"
+    [ testCase "2025" $
+        S.toAscList (holidays "DEU" regions 2025)
+          @?= [ day 2025 1 1,
+                day 2025 1 6,
+                day 2025 3 8,
+                day 2025 4 18,
+                day 2025 4 20,
+                day 2025 4 21,
+                day 2025 5 1,
+                day 2025 5 8,
+                day 2025 5 29,
+                day 2025 6 8,
+                day 2025 6 9,
+                day 2025 6 19,
+                day 2025 8 15,
+                day 2025 9 20,
+                day 2025 10 3,
+                day 2025 10 31,
+                day 2025 11 1,
+                day 2025 11 19,
+                day 2025 12 25,
+                day 2025 12 26
+              ]
+    ]
+
+propTests :: TestTree
+propTests = countryPropTests "DEU" regions
diff --git a/tst/Test/Holidays/Namibia.hs b/tst/Test/Holidays/Namibia.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays/Namibia.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.Holidays.Namibia (
+  unitTests,
+  propTests,
+) where
+
+import Data.Set qualified as S
+import Holidays
+import Test.Holidays
+import Test.Tasty
+import Test.Tasty.HUnit
+
+unitTests :: TestTree
+unitTests =
+  testGroup
+    "NAM unit tests"
+    [ testCase "2024" $
+        S.toAscList (holidays "NAM" [] 2024)
+          @?= [ day 2024 1 1,
+                day 2024 3 21,
+                day 2024 3 29,
+                day 2024 4 1,
+                day 2024 5 1,
+                day 2024 5 4,
+                day 2024 5 9,
+                day 2024 5 25,
+                day 2024 8 26,
+                day 2024 12 10,
+                day 2024 12 25,
+                day 2024 12 26
+              ],
+      testCase "2025" $
+        S.toAscList (holidays "NAM" [] 2025)
+          @?= [ day 2025 1 1,
+                day 2025 3 21,
+                day 2025 4 18,
+                day 2025 4 21,
+                day 2025 5 1,
+                day 2025 5 5,
+                day 2025 5 26,
+                day 2025 5 28,
+                day 2025 5 29,
+                day 2025 8 26,
+                day 2025 12 10,
+                day 2025 12 25,
+                day 2025 12 26
+              ]
+    ]
+
+propTests :: TestTree
+propTests = countryPropTests "NAM" []
diff --git a/tst/Test/Holidays/SouthAfrica.hs b/tst/Test/Holidays/SouthAfrica.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays/SouthAfrica.hs
@@ -0,0 +1,52 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.Holidays.SouthAfrica (
+  unitTests,
+  propTests,
+) where
+
+import Data.Set qualified as S
+import Holidays
+import Test.Holidays
+import Test.Tasty
+import Test.Tasty.HUnit
+
+unitTests :: TestTree
+unitTests =
+  testGroup
+    "ZAF unit tests"
+    [ testCase "2024" $
+        S.toAscList (holidays "ZAF" [] 2024)
+          @?= [ day 2024 1 1,
+                day 2024 3 21,
+                day 2024 3 29,
+                day 2024 4 1,
+                day 2024 4 27,
+                day 2024 5 1,
+                day 2024 5 29,
+                day 2024 6 17,
+                day 2024 8 9,
+                day 2024 9 24,
+                day 2024 12 16,
+                day 2024 12 25,
+                day 2024 12 26
+              ],
+      testCase "2025" $
+        S.toAscList (holidays "ZAF" [] 2025)
+          @?= [ day 2025 1 1,
+                day 2025 3 21,
+                day 2025 4 18,
+                day 2025 4 21,
+                day 2025 4 28,
+                day 2025 5 1,
+                day 2025 6 16,
+                day 2025 8 9,
+                day 2025 9 24,
+                day 2025 12 16,
+                day 2025 12 25,
+                day 2025 12 26
+              ]
+    ]
+
+propTests :: TestTree
+propTests = countryPropTests "ZAF" []
diff --git a/tst/Test/Holidays/UnitedKingdom.hs b/tst/Test/Holidays/UnitedKingdom.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays/UnitedKingdom.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.Holidays.UnitedKingdom (
+  unitTests,
+  propTests,
+) where
+
+import Data.Set qualified as S
+import Holidays
+import Test.Holidays
+import Test.Tasty
+import Test.Tasty.HUnit
+
+unitTests :: TestTree
+unitTests =
+  testGroup
+    "GBR unit tests"
+    [ testCase "2025" $
+        S.toAscList (holidays "GBR" [] 2025)
+          @?= [ day 2025 1 1,
+                day 2025 4 18,
+                day 2025 4 21,
+                day 2025 5 5,
+                day 2025 5 26,
+                day 2025 8 25,
+                day 2025 12 25,
+                day 2025 12 26
+              ],
+      testCase "2026" $
+        S.toAscList (holidays "GBR" [] 2026)
+          @?= [ day 2026 1 1,
+                day 2026 4 3,
+                day 2026 4 6,
+                day 2026 5 4,
+                day 2026 5 25,
+                day 2026 8 31,
+                day 2026 12 25,
+                day 2026 12 28
+              ]
+    ]
+
+propTests :: TestTree
+propTests = countryPropTests "GBR" []
diff --git a/tst/Test/Holidays/UnitedStates.hs b/tst/Test/Holidays/UnitedStates.hs
new file mode 100644
--- /dev/null
+++ b/tst/Test/Holidays/UnitedStates.hs
@@ -0,0 +1,35 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module Test.Holidays.UnitedStates (
+  unitTests,
+  propTests,
+) where
+
+import Data.Set qualified as S
+import Holidays
+import Test.Holidays
+import Test.Tasty
+import Test.Tasty.HUnit
+
+unitTests :: TestTree
+unitTests =
+  testGroup
+    "USA unit tests"
+    [ testCase "2025" $
+        S.toAscList (holidays "USA" [] 2025)
+          @?= [ day 2025 1 1,
+                day 2025 1 20,
+                day 2025 2 17,
+                day 2025 5 26,
+                day 2025 6 19,
+                day 2025 7 4,
+                day 2025 9 1,
+                day 2025 10 13,
+                day 2025 11 11,
+                day 2025 11 27,
+                day 2025 12 25
+              ]
+    ]
+
+propTests :: TestTree
+propTests = countryPropTests "USA" []
