Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add a method to check if a time.time is a bank holiday for a specific region #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 63 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,56 +7,58 @@ The library is probably useful only for people realizing use cases with special
See https://godoc.org/github.com/wlbr/feiertage

### Usage:
There are two types of functions:
There are four types of functions:

* `<feiertag>(year)` and
* `<region>(year optional:IncludingSundays:true)`
* `GetRegionFromString(region, year)`
* `CheckIfIsBankHolidayIn(date, state)`

`<feiertag>` returns an extended `time` object (type `feiertag`). It carries the date of the holiday
in the requested year plus the name of the holiday. `<feiertag>` may be any of the following:

||||
|----|-----|----|
`Neujahr` | `Epiphanias` | `HeiligeDreiKönige`
`Valentinstag` | `InternationalerTagDesGedenkensAnDieOpferDesHolocaust` | `Josefitag`
`Weiberfastnacht` | `Karnevalssonntag` | `Rosenmontag`
`Fastnacht` | `Aschermittwoch` | `InternationalerFrauentag`
`Palmsonntag` | `Gründonnerstag` | `Karfreitag`
`Ostern` | `BeginnSommerzeit` | `Ostermontag`
`Walpurgisnacht` | `TagDerArbeit` | `TagDerBefreiung`
`Staatsfeiertag` | `InternationalerTagDerPressefreiheit` | `Florianitag`
`Muttertag` | `Handtuchtag` | `ChristiHimmelfahrt`
`Vatertag` | `Pfingsten` | `Pfingstmontag`
`Dreifaltigkeitssonntag` | `Fronleichnam` | `TagDesMeeres`
`MariäHimmelfahrt` | `SystemAdministratorAppreciationDay` |`Rupertitag`
`InternationalerKindertag`| `Weltflüchtlingstag` | `TagDerDeutschenEinheit`
`TagDerVolksabstimmung` | `Nationalfeiertag` | `Erntedankfest`
`Reformationstag` | `Halloween` | `BeginnWinterzeit`
`Allerheiligen` | `Allerseelen` | `Martinstag`
`Karnevalsbeginn` | `Leopolditag` | `Weltkindertag`
`BußUndBettag` | `Thanksgiving` | `Blackfriday`
`Volkstrauertag` | `Nikolaus` | `MariäUnbefleckteEmpfängnis`
`MariäEmpfängnis` | `Totensonntag` | `ErsterAdvent`
`ZweiterAdvent` | `DritterAdvent` | `VierterAdvent`
`Heiligabend` | `Weihnachten` | `Christtag`
`Stefanitag` | `ZweiterWeihnachtsfeiertag` | `Silvester`
|`Neujahr` | `Epiphanias` | `HeiligeDreiKönige`|
|`Valentinstag` | `InternationalerTagDesGedenkensAnDieOpferDesHolocaust` | `Josefitag`|
|`Weiberfastnacht` | `Karnevalssonntag` | `Rosenmontag`|
|`Fastnacht` | `Aschermittwoch` | `InternationalerFrauentag`|
|`Palmsonntag` | `Gründonnerstag` | `Karfreitag`|
|`Ostern` | `BeginnSommerzeit` | `Ostermontag`|
|`Walpurgisnacht` | `TagDerArbeit` | `TagDerBefreiung`|
|`Staatsfeiertag` | `InternationalerTagDerPressefreiheit` | `Florianitag`|
|`Muttertag` | `Handtuchtag` | `ChristiHimmelfahrt`|
| `Vatertag` | `Pfingsten` | `Pfingstmontag`|
|`Dreifaltigkeitssonntag` | `Fronleichnam` | `TagDesMeeres`|
|`MariäHimmelfahrt` | `SystemAdministratorAppreciationDay` |`Rupertitag`|
|`InternationalerKindertag`| `Weltflüchtlingstag` | `TagDerDeutschenEinheit`|
|`TagDerVolksabstimmung` | `Nationalfeiertag` | `Erntedankfest`|
|`Reformationstag` | `Halloween` | `BeginnWinterzeit`|
|`Allerheiligen` | `Allerseelen` | `Martinstag`|
|`Karnevalsbeginn` | `Leopolditag` | `Weltkindertag`|
|`BußUndBettag` | `Thanksgiving` | `Blackfriday`|
|`Volkstrauertag` | `Nikolaus` | `MariäUnbefleckteEmpfängnis`|
|`MariäEmpfängnis` | `Totensonntag` | `ErsterAdvent`|
|`ZweiterAdvent` | `DritterAdvent` | `VierterAdvent`|
|`Heiligabend` | `Weihnachten` | `Christtag`|
|`Stefanitag` | `ZweiterWeihnachtsfeiertag` | `Silvester`|


`<region>` returns an object of type `region`. It offers a list of public holidays valid in the specified state as well as the name and the shortname of the state as attributes.
`<region>` may be any of:

||||
----|-----|----
`BadenWürttemberg` | `Bayern` | `Berlin`
`Brandenburg` | `Bremen` | `Hamburg`
`Hessen` | `MecklenburgVorpommern` | `Niedersachsen`
`NordrheinWestfalen` | `RheinlandPfalz` | `Saarland`
`Sachsen` | `SachsenAnhalt` | `SchleswigHolstein`
`Thüringen` | `Deutschland` | `Burgenland`
`Kärnten` | `Niederösterreich` | `Oberösterreich`
`Salzburg` | `Steiermark` | `Tirol`
`Vorarlberg` | `Wien` | `Österreich`
`All` | &nbsp; | &nbsp;
|----|-----|----|
|`BadenWürttemberg` | `Bayern` | `Berlin`|
|`Brandenburg` | `Bremen` | `Hamburg`|
|`Hessen` | `MecklenburgVorpommern` | `Niedersachsen`|
|`NordrheinWestfalen` | `RheinlandPfalz` | `Saarland`|
|`Sachsen` | `SachsenAnhalt` | `SchleswigHolstein`|
|`Thüringen` | `Deutschland` | `Burgenland`|
|`Kärnten` | `Niederösterreich` | `Oberösterreich`|
|`Salzburg` | `Steiermark` | `Tirol`|
|`Vorarlberg` | `Wien` | `Österreich`|
|`All` | &nbsp; | &nbsp;|

The optional region function argument `includingSundays` switches the behavior of the region function to include "gesetzliche Feiertage" that fall on Sundays in its output. This is important in Brandenburg, particularly for Easter and Pentecost Sunday. If you are calculating shift costs you will need to know even the holidays "hidden by Sunday".

Expand All @@ -67,6 +69,13 @@ schools etc. are generally closed but workers don't get the day off by default.
include these days in your planning, it's okay to reference `Österreich` instead, as legal holidays are
(more or less) synchronised across all Austrian states (Bundesländer).


GetRegionFromString tries to match a string to a region from Germany or Austria. Because a reagion already contains the feiertage, a `year` is needed to calc theese.

CheckIfIsBankHolidayIn checks if the given `date` is a Bank holiday in the `region`, Sundays are only positve in case they are on a feiertag for the region as well.



### Examples:

fmt.Println(Ostern(2016))
Expand Down Expand Up @@ -107,6 +116,25 @@ include these days in your planning, it's okay to reference `Österreich` instea
25.12.2016 Weihnachten
26.12.2016 Zweiter Weihnachtsfeiertag

region, _ := GetRegionFromString("Brandenburg",2016)
fmt.Println(region)
--> Brandenburg (BB)
01.01.2016 Neujahr
25.03.2016 Karfreitag
28.03.2016 Ostermontag
01.05.2016 Tag der Arbeit
05.05.2016 Christi Himmelfahrt
16.05.2016 Pfingstmontag
03.10.2016 Tag der deutschen Einheit
31.10.2016 Reformationstag
25.12.2016 Weihnachten
26.12.2016 Zweiter Weihnachtsfeiertag

fmt.Println(CheckIfIsBankHolidayIn(time.Date(2016,1,1,0,0,0,0,time.UTC),Brandenburg(2016, false)))
--> true




## Command line tool

Expand Down
38 changes: 38 additions & 0 deletions checkBackHoliday.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package feiertage

import (
"github.com/pkg/errors"
"time"
)

func CheckIfIsBankHoliday(date time.Time, region Region) bool {

for _, feiertag := range region.Feiertage {
if datesAreEqual(feiertag.Time, date) {
return true
}
}
return false

}

func datesAreEqual(date1, date2 time.Time) bool {
if date1.Year() != date2.Year() {
return false
}
if date1.Month() != date2.Month() {
return false
}
if date1.Day() != date2.Day() {
return false
}
return true
}
func CheckIfIsBankHolidayIn(date time.Time, state string) (bool, error) {

region, err := GetRegionFromString(state, date.Year())
if err != nil {
return false, errors.Wrap(err, "Failed to parse region from state string")
}
return CheckIfIsBankHoliday(date, region), nil
}
20 changes: 20 additions & 0 deletions checkBackHoliday_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package feiertage

import (
"github.com/stretchr/testify/assert"
"testing"
"time"
)

func TestCheckIfIsBankHoliday(t *testing.T) {
isBankHoliday := CheckIfIsBankHoliday(time.Date(2022, 10, 31, 0, 0, 0, 0, time.UTC), Niedersachsen(2022))
assert.True(t, isBankHoliday)
isBankHoliday = CheckIfIsBankHoliday(time.Date(2022, 12, 25, 0, 0, 0, 0, time.UTC), Niedersachsen(2022))
assert.True(t, isBankHoliday)
isBankHoliday = CheckIfIsBankHoliday(time.Date(2022, 12, 26, 0, 0, 0, 0, time.UTC), Niedersachsen(2022))
assert.True(t, isBankHoliday)
isBankHoliday = CheckIfIsBankHoliday(time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC), Niedersachsen(2023))
assert.True(t, isBankHoliday)
isBankHoliday = CheckIfIsBankHoliday(time.Date(2022, 10, 30, 0, 0, 0, 0, time.UTC), Niedersachsen(2022))
assert.False(t, isBankHoliday)
}
2 changes: 1 addition & 1 deletion cmd/feiertage/feiertage.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func getRegion(region string, year int, includingSundays bool) (feiertage.Region
return r, nil
}
}
return r, fmt.Errorf("Region '%s' unbekannt.", region)
return r, fmt.Errorf("Region '%s' unknown", region)
}

func main() {
Expand Down
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
module github.com/wlbr/feiertage

go 1.15

require (
github.com/pkg/errors v0.9.1
github.com/stretchr/testify v1.8.1
)
66 changes: 66 additions & 0 deletions region.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package feiertage

import (
"fmt"
"github.com/pkg/errors"
"sort"
"strings"
)
Expand Down Expand Up @@ -372,3 +373,68 @@ func GetAllRegions(year int, inklSonntag bool, country ...string) (regions []Reg

return regions
}

func GetRegionFromString(region string, y int) (Region, error) {

region = strings.ToLower(region)
region = strings.ReplaceAll(region, " ", "")
region = strings.ReplaceAll(region, "-", "")
region = strings.ReplaceAll(region, "ä", "ae")
region = strings.ReplaceAll(region, "ü", "ue")
region = strings.ReplaceAll(region, "ö", "oe")
switch region {
case "badenwuerttemberg":
return BadenWürttemberg(y), nil
case "bayern":
return Bayern(y), nil
case "berlin":
return Berlin(y), nil
case "brandenburg":
return Brandenburg(y), nil
case "bremen":
return Bremen(y), nil
case "hamburg":
return Hamburg(y), nil
case "hessen":
return Hessen(y), nil
case "mecklenburgvorpommern":
return MecklenburgVorpommern(y), nil
case "niedersachsen":
return Niedersachsen(y), nil
case "nordrheinwestfalen":
return NordrheinWestfalen(y), nil
case "rheinlandpfalz":
return RheinlandPfalz(y), nil
case "saarland":
return Saarland(y), nil
case "sachsen":
return Sachsen(y), nil
case "sachsenanhalt":
return SachsenAnhalt(y), nil
case "schleswigholstein":
return SchleswigHolstein(y), nil
case "thueringen":
return Thüringen(y), nil
case "burgenland":
return Burgenland(y), nil
case "kaernten":
return Kärnten(y), nil
case "niederoesterreich":
return Niederösterreich(y), nil
case "oberoesterreich":
return Oberösterreich(y), nil
case "salzburg":
return Salzburg(y), nil
case "steiermark":
return Steiermark(y), nil
case "tirol":
return Tirol(y), nil
case "vorarlberg":
return Vorarlberg(y), nil
case "wien":
return Wien(y), nil
case "oesterreich":
return Österreich(y), nil
}
return Region{}, errors.New(fmt.Sprintf("Not found region for: '%s'", region))
}
97 changes: 97 additions & 0 deletions region_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package feiertage

import (
"fmt"
"github.com/stretchr/testify/assert"
"testing"
)

Expand Down Expand Up @@ -92,3 +93,99 @@ func TestFeiertageZahl(t *testing.T) {
fmt.Println(Brandenburg(2017))

}

func TestGetRegionFromString(t *testing.T) {
_, err := GetRegionFromString("", 2022)
assert.Error(t, err)
_, err = GetRegionFromString("Sachen-Anhalt", 2022)
assert.Error(t, err)

region, err := GetRegionFromString("Sachsen-Anhalt", 2022)
assert.Equal(t, region, SachsenAnhalt(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Sachsen Anhalt", 2022)
assert.Equal(t, region, SachsenAnhalt(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("SachsenAnhalt", 2022)
assert.Equal(t, region, SachsenAnhalt(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Baden Württemberg", 2022)
assert.Equal(t, region, BadenWürttemberg(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Bayern", 2022)
assert.Equal(t, region, Bayern(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("bayern", 2022)
assert.Equal(t, region, Bayern(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Berlin", 2022)
assert.Equal(t, region, Berlin(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Brandenburg", 2022)
assert.Equal(t, region, Brandenburg(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Bremen", 2022)
assert.Equal(t, region, Bremen(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Hamburg", 2022)
assert.Equal(t, region, Hamburg(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Niedersachsen", 2022)
assert.Equal(t, region, Niedersachsen(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("NordrheinWestfalen", 2022)
assert.Equal(t, region, NordrheinWestfalen(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("RheinlandPfalz", 2022)
assert.Equal(t, region, RheinlandPfalz(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Saarland", 2022)
assert.Equal(t, region, Saarland(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Sachsen", 2022)
assert.Equal(t, region, Sachsen(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("SachsenAnhalt", 2022)
assert.Equal(t, region, SachsenAnhalt(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("SchleswigHolstein", 2022)
assert.Equal(t, region, SchleswigHolstein(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Thüringen", 2022)
assert.Equal(t, region, Thüringen(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Thüringen", 2022)
assert.Equal(t, region, Thüringen(2022))

region, err = GetRegionFromString("Burgenland", 2022)
assert.Equal(t, region, Burgenland(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Kärnten", 2022)
assert.Equal(t, region, Kärnten(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Niederösterreich", 2022)
assert.Equal(t, region, Niederösterreich(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Oberösterreich", 2022)
assert.Equal(t, region, Oberösterreich(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Salzburg", 2022)
assert.Equal(t, region, Salzburg(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Steiermark", 2022)
assert.Equal(t, region, Steiermark(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Tirol", 2022)
assert.Equal(t, region, Tirol(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Vorarlberg", 2022)
assert.Equal(t, region, Vorarlberg(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Wien", 2022)
assert.Equal(t, region, Wien(2022))
assert.NoError(t, err)
region, err = GetRegionFromString("Österreich", 2022)
assert.Equal(t, region, Österreich(2022))
assert.NoError(t, err)

}