bank-holiday-germany 1.2.0.0 → 1.3.0.0
raw patch · 5 files changed
+195/−41 lines, 5 filesdep ~doctestdep ~hedgehogdep ~hspec-hedgehogPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: doctest, hedgehog, hspec-hedgehog, time
API changes (from Hackage documentation)
+ Data.Time.Calendar.BankHoliday.Germany.ExtraHolidays: BussUndBettag :: ExtraHoliday
Files
- CHANGELOG.md +15/−0
- README.md +74/−4
- bank-holiday-germany.cabal +1/−1
- src/Data/Time/Calendar/BankHoliday/Germany/ExtraHolidays.hs +59/−31
- test/Main.hs +46/−5
CHANGELOG.md view
@@ -29,3 +29,18 @@ - Add `ExtraHoliday` for Bundesland Berlin - Add and enhance docs++## [1.2.0.0] - 2024-03-22++### Added++- Add extra holidays for Baden-Württemberg, Nordrhein-Westfalen,+ Hessen, and Niedersachsen+- Update doc++## [1.3.0.0] - 2024-04-01++### Added++- Add extra holidays for all remaining federal states.+- Update doc
README.md view
@@ -10,10 +10,10 @@ holiday is also a legal holiday. Legal holidays are generally off for all employees. Bank holidays that-are not legal holidays as well are generally only off for bank employees.+are not legal holidays are generally only off for bank employees. There are even more public holidays in each federal state which-are (partly) covered by the `ExtraHolidays` module of this package.+are covered by the `ExtraHolidays` module of this package. See the [module documentation](https://hackage.haskell.org/package/bank-holiday-germany) on Hackage for more information.@@ -30,7 +30,7 @@ Gesetzliche Feiertage sind Ländersache – abgesehen vom [Nationalfeiertag](https://www.bmi.bund.de/DE/themen/verfassung/staatliche-symbole/nationale-feiertage/nationale-feiertage-node.html)-*Tag der deutschen Einheit*.+*Tag der Deutschen Einheit*. Bankfeiertage sind in der Regel für Bankangestellte frei. Gesetzliche Feiertage sind in der Regel für alle Angestellten frei (im@@ -39,9 +39,79 @@ Gesetzliche Feiertage der Bundesländer, die nicht gleichzeitig Bankfeiertage sind, sind im Modul `ExtraHolidays` definiert. -Vorsicht: Manche gesetzliche Feiertage gelten nicht für das ganze+**Für alle 16 Bundesländer sind damit die jeweiligen Feiertage+vollständig implementiert (Stand 2024-03-31).**++Vorsicht: Manche gesetzliche Feiertage gelten nicht für ein ganzes Bundesland sondern nur für bestimmte Landkreise, z.B. das Friedensfest in Augsburg. Ein Code-Beispiel im Modul `ExtraHolidays` zeigt, wie alle Feiertage für ein bestimmtes Bundesland berechnet werden können.++## Sample code++Rank federal states by number of holidays:++`test.hs`:++```haskell+import Prelude+import Data.List+import Data.Time+import qualified Data.Time.Calendar.BankHoliday.Germany as BH+import qualified Data.Time.Calendar.BankHoliday.Germany.ExtraHolidays as EH+import Data.Time.Calendar.BankHoliday.Germany (BankHoliday(..))+import Data.Time.Calendar.BankHoliday.Germany.ExtraHolidays (FederalState(..), ExtraHoliday(..))++holidays :: Year -> FederalState -> [Day]+holidays year state = map fst (filter (BH.isPublicHoliday . snd) $ BH.holidaysBetween start end)+ ++ map fst (EH.holidaysBetween state start end)+ where+ start = fromGregorian year 1 1+ end = fromGregorian year 12 31+++supportedFederalStates :: [FederalState]+supportedFederalStates = [minBound .. maxBound]++year :: Year+year = 2024++showPadded :: Int -> String+showPadded n | n < 10 = " " ++ show n+ | otherwise = show n++main :: IO ()+main = putStrLn+ $ unlines+ $ map (\(x, n) -> showPadded n ++ " " ++ show x)+ $ sortOn ((0-) . snd)+ $ map (\x -> (x, length $ holidays year x))+ $ supportedFederalStates+```++```+$ stack script --resolver=lts-22.0 --package time --package bank-holiday-germany test.hs+14 Bayern+12 BadenWuerttemberg+12 Saarland+11 MecklenburgVorpommern+11 NordrheinWestfalen+11 RheinlandPfalz+11 Sachsen+11 SachsenAnhalt+11 Thueringen+10 Berlin+10 Brandenburg+10 Bremen+10 Hamburg+10 Hessen+10 Niedersachsen+10 SchleswigHolstein+```++More examples:++- [Bank holidays](https://hackage.haskell.org/package/bank-holiday-germany/docs/Data-Time-Calendar-BankHoliday-Germany.html)+- [Extra holidays](https://hackage.haskell.org/package/bank-holiday-germany/docs/Data-Time-Calendar-BankHoliday-Germany-ExtraHolidays.html)
bank-holiday-germany.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.6 name: bank-holiday-germany-version: 1.2.0.0+version: 1.3.0.0 synopsis: German bank holidays and public holidays description: Calculation of bank holidays and most public holidays in Germany. homepage: https://github.com/schoettl/bank-holiday-germany#readme
src/Data/Time/Calendar/BankHoliday/Germany/ExtraHolidays.hs view
@@ -16,12 +16,8 @@ For example, Heilige Drei Könige is not a bank holiday but it is a public holiday in Bavaria. -Note: The extra holidays are currently only implemented for-Baden-Württemberg, Bayern, Berlin, Niedersachsen, Hessen, and-Nordrhein-Westfalen.--Example for computing all public holidays in Bavaria (Landkreis-Miesbach, Oberbayern) in the next couple years:+The example prints all public holidays in Bavaria (Landkreis+Miesbach, Oberbayern) in 2025: @ import Prelude@@ -30,7 +26,7 @@ import qualified Data.Time.Calendar.BankHoliday.Germany as BH import qualified Data.Time.Calendar.BankHoliday.Germany.ExtraHolidays as EH -start = fromGregorian 2024 1 1+start = fromGregorian 2025 1 1 end = fromGregorian 2025 12 31 @@ -43,19 +39,6 @@ @ @-2024-01-01 Neujahrstag-2024-01-06 Heilige Drei Könige-2024-03-29 Karfreitag-2024-04-01 Ostermontag-2024-05-01 Tag der Arbeit-2024-05-09 Christi Himmelfahrt-2024-05-20 Pfingstmontag-2024-05-30 Fronleichnam-2024-08-15 Mariä Himmelfahrt-2024-10-03 Tag der Deutschen Einheit-2024-11-01 Allerheiligen-2024-12-25 1. Weihnachtsfeiertag-2024-12-26 2. Weihnachtsfeiertag 2025-01-01 Neujahrstag 2025-01-06 Heilige Drei Könige 2025-04-18 Karfreitag@@ -73,12 +56,24 @@ Resources: +Extra holidays are implemented for all 16 federal states. For some+states, we couldn't find official sources; That's why this list+only includes some states.+ - Übersicht: https://de.wikipedia.org/wiki/Gesetzliche_Feiertage_in_Deutschland - Weitere Übersicht: https://www.arbeitstage.org/ - Bayern: https://www.stmi.bayern.de/suv/feiertage/ - Baden-Württemberg: https://im.baden-wuerttemberg.de/de/service/feiertage - Niedersachsen: https://service.niedersachsen.de/portaldeeplink/?tsa_leistung_id=8664664&tsa_sprache=de_DE - Hessen: https://innen.hessen.de/buerger-staat/feiertage+ - Rheinland-Pfalz: https://mdi.rlp.de/themen/buerger-und-staat/verfassung-und-verwaltung/sonn-und-feiertagsrecht+ - Brandenburg: https://bravors.brandenburg.de/gesetze/ftg_2003/6+ - Sachsen-Anhalt: https://www.landesrecht.sachsen-anhalt.de/bsst/document/jlr-FeiertGSTrahmen/part/X+ - Thüringen: https://buerger.thueringen.de/detail?pstId=354718+ - Hamburg: https://www.hamburg.de/ferien-und-feiertage/+ - Mecklenburg-Vorpommern u. Berlin (Frauentag): https://www.deutsche-rentenversicherung.de/DRV/DE/Ueber-uns-und-Presse/Presse/Meldungen/2024/240306_frauentag_feiertag_frei.html+ - Saarland: https://www.saarland.de/mibs/DE/themen-aufgaben/aufgaben/buerger_und_staat/sonn_u_feiertagsrecht/feiertagsrecht_node.html+ - Bremen: https://www.transparenz.bremen.de/metainformationen/gesetz-ueber-die-sonn-gedenk-und-feiertage-vom-12-november-1954-145882?asl=bremen203_tpgesetz.c.55340.de&template=20_gp_ifg_meta_detail_d -} @@ -117,22 +112,20 @@ | Thueringen deriving (Enum, Eq, Bounded, Show, Read) --- TODO: Remove note below when all federal states are fully implemented.- -- | Extra federal holidays, no overlap with -- 'Data.Time.Calendar.BankHoliday.Germany.BankHoliday'. -- Spezielle Feiertage der Bundesländer. ----- Note: Currently, only some federal states' extra holidays are implemented.--- See module description above for details.+-- \*regional holiday, only applies in parts of the federal state data ExtraHoliday- = HeiligeDreiKoenige -- ^ Heilige Drei Könige (Bayern, Baden-Württemberg, …)- | Fronleichnam -- ^ Fronleichnam (Bayern, Baden-Württemberg, Nordrhein-Westfalen, Hessen, …)- | Friedensfest -- ^ Friedensfest (Bayern (Augsburg), …)- | MariaeHimmelfahrt -- ^ Mariä Himmelfahrt (Bayern (regional), …)- | Allerheiligen -- ^ Allerheiligen (Bayern, Baden-Württemberg, Nordrhein-Westfalen, …)- | Reformationstag -- ^ Reformationstag (Niedersachsen, …)- | InternationalerFrauentag -- ^ Internationaler Frauentag (Berlin, …)+ = HeiligeDreiKoenige -- ^ Heilige Drei Könige (Bayern, Baden-Württemberg, Sachsen-Anhalt)+ | Fronleichnam -- ^ Fronleichnam (Bayern, Baden-Württemberg, Nordrhein-Westfalen, Hessen, Rheinland-Pfalz, Thüringen*, Saarland)+ | Friedensfest -- ^ Friedensfest (Bayern*)+ | MariaeHimmelfahrt -- ^ Mariä Himmelfahrt (Bayern*, Saarland)+ | Allerheiligen -- ^ Allerheiligen (Bayern, Baden-Württemberg, Nordrhein-Westfalen, Rheinland-Pfalz, Saarland)+ | Reformationstag -- ^ Reformationstag (Niedersachsen, Sachsen, Schleswig-Holstein, Brandenburg, Sachsen-Anhalt, Thüringen, Hamburg, Mecklenburg-Vorpommern, Bremen)+ | InternationalerFrauentag -- ^ Internationaler Frauentag (Berlin, Mecklenburg-Vorpommern)+ | BussUndBettag -- ^ Buß- und Bettag (Sachsen) deriving (Enum, Eq, Bounded, Show, Read) -- | Compute the date for a given year and extra holiday.@@ -147,6 +140,7 @@ toDay year Allerheiligen = fromGregorian year 11 1 toDay year InternationalerFrauentag = fromGregorian year 3 8 toDay year Reformationstag = fromGregorian year 10 31+toDay year BussUndBettag = calculateBussUndBettag year -- | Compute 'Maybe' the holiday for a given date. --@@ -179,9 +173,15 @@ Allerheiligen -> "Allerheiligen" Reformationstag -> "Reformationstag" InternationalerFrauentag -> "Internationaler Frauentag"+ BussUndBettag -> "Buß- und Bettag" -- | Check if 'ExtraHoliday' is a holiday in the given federal state. --+-- Note: Internationaler Frauentag is a holiday in Berlin (since 2019)+-- and Mecklenburg-Vorpommern (since 2023).+-- However this function doesn't take the year into account and hence+-- is incorrect for earlier years.+-- -- >>> isHolidayInState Bayern Allerheiligen -- True --@@ -201,4 +201,32 @@ isHolidayInState NordrheinWestfalen Allerheiligen = True isHolidayInState Niedersachsen Reformationstag = True isHolidayInState Hessen Fronleichnam = True+isHolidayInState RheinlandPfalz Allerheiligen = True+isHolidayInState RheinlandPfalz Fronleichnam = True+isHolidayInState Sachsen Reformationstag = True+isHolidayInState Sachsen BussUndBettag = True+isHolidayInState SchleswigHolstein Reformationstag = True+isHolidayInState Brandenburg Reformationstag = True+isHolidayInState SachsenAnhalt HeiligeDreiKoenige = True+isHolidayInState SachsenAnhalt Reformationstag = True+isHolidayInState Thueringen Fronleichnam = True+isHolidayInState Thueringen Reformationstag = True+isHolidayInState Hamburg Reformationstag = True+isHolidayInState MecklenburgVorpommern Reformationstag = True+isHolidayInState MecklenburgVorpommern InternationalerFrauentag = True+isHolidayInState Saarland Fronleichnam = True+isHolidayInState Saarland Allerheiligen = True+isHolidayInState Saarland MariaeHimmelfahrt = True+isHolidayInState Bremen Reformationstag = True isHolidayInState _ _ = False++-- | Calculate Buß- und Bettag.+--+-- https://de.wikipedia.org/wiki/Bu%C3%9F-_und_Bettag+calculateBussUndBettag :: Year -> Day+calculateBussUndBettag year =+ let november23 = fromGregorian year 11 23+ weekDay = dayOfWeek november23+ in if weekDay <= Wednesday+ then addDays (toInteger $ fromEnum Wednesday - fromEnum weekDay - 7) november23+ else addDays (toInteger $ fromEnum Wednesday - fromEnum weekDay) november23
test/Main.hs view
@@ -74,6 +74,9 @@ m <- forAll $ Gen.integral (Range.linear 1 12) d <- forAll $ Gen.integral (Range.linear 1 28) yearFromDay (day y m d) === y+ describe "germanHolidayName" $+ it "names are longer than 5 characters for all holidays (which mean there are no non-exhaustive patterns)" $+ all ((>5) . length . germanHolidayName) [minBound .. maxBound :: BankHoliday] `shouldBe` True describe "Data.Time.Calendar.BankHoliday.Germany.ExtraHolidays" $ do describe "FederalState" $@@ -103,8 +106,46 @@ it "there is only Fronleichnam in Hessen" $ hedgehog $ do y <- forAll $ Gen.integral (Range.linear 2024 5000) (map snd $ EH.holidaysBetween Hessen (jan1 y) (dec31 y)) === [Fronleichnam]- it "has no holidays for other states yet => otherwise, please add tests" $ do- let statesExceptBavaria = filter (not . (`elem` [BadenWuerttemberg, Bayern, Berlin, NordrheinWestfalen, Niedersachsen, Hessen])) [minBound .. maxBound :: FederalState]- let holidays = concatMap (\x -> EH.holidaysBetween x (day 2024 1 1) (day 2024 12 31)) statesExceptBavaria- holidays `shouldBe` []- -- TODO: add test for germanHolidayName that uses random holidays to detect non-exhaustive patterns+ it "has holidays for Rheinland-Pfalz" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween RheinlandPfalz (jan1 y) (dec31 y)) === [Fronleichnam, Allerheiligen]+ it "has holidays for Sachsen" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween Sachsen (jan1 y) (dec31 y)) === [Reformationstag, BussUndBettag]+ it "has holidays for Schleswig-Holstein" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween SchleswigHolstein (jan1 y) (dec31 y)) === [Reformationstag]+ it "has holidays for Brandenburg" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween Brandenburg (jan1 y) (dec31 y)) === [Reformationstag]+ it "has holidays for Sachsen-Anhalt" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween SachsenAnhalt (jan1 y) (dec31 y)) === [HeiligeDreiKoenige, Reformationstag]+ it "has holidays for Thüringen" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween Thueringen (jan1 y) (dec31 y)) === [Fronleichnam, Reformationstag]+ it "has holidays for Hamburg" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2024 5000)+ (map snd $ EH.holidaysBetween Hamburg (jan1 y) (dec31 y)) === [Reformationstag]+ it "has holidays for Mecklenburg-Vorpommern" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2023 5000)+ (map snd $ EH.holidaysBetween MecklenburgVorpommern (jan1 y) (dec31 y)) === [InternationalerFrauentag, Reformationstag]+ it "has holidays for Saarland" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2023 5000)+ (map snd $ EH.holidaysBetween Saarland (jan1 y) (dec31 y)) === [Fronleichnam, MariaeHimmelfahrt, Allerheiligen]+ it "has holidays for Bremen" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 2023 5000)+ (map snd $ EH.holidaysBetween Bremen (jan1 y) (dec31 y)) === [Reformationstag]+ it "computes Buss- und Bettag correctly for some years" $ do+ EH.toDay 2024 BussUndBettag `shouldBe` day 2024 11 20+ EH.toDay 2025 BussUndBettag `shouldBe` day 2025 11 19+ EH.toDay 2026 BussUndBettag `shouldBe` day 2026 11 18+ EH.toDay 2033 BussUndBettag `shouldBe` day 2033 11 16+ it "Buss- und Bettag is always between 16. and 22. November (inclusive)" $ hedgehog $ do+ y <- forAll $ Gen.integral (Range.linear 0 5000)+ let (_, m, d) = toGregorian $ EH.toDay y BussUndBettag+ (d >= 16 && d <= 22) === True+ m === 11+ describe "germanHolidayName" $+ it "names are longer than 5 characters for all holidays (which mean there are no non-exhaustive patterns)" $+ all ((>5) . length . EH.germanHolidayName) [minBound .. maxBound :: ExtraHoliday] `shouldBe` True