Skip to content

Commit

Permalink
Merge pull request #114 from DanailPenev/DanailPenev/add-bulgarian-ho…
Browse files Browse the repository at this point in the history
…lidays

Add Bulgarian holidays
  • Loading branch information
rickar committed Apr 5, 2023
2 parents 1b31496 + fdcdacd commit 5cbae22
Show file tree
Hide file tree
Showing 2 changed files with 267 additions and 0 deletions.
151 changes: 151 additions & 0 deletions v2/bg/bg_holidays.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package bg

import (
"time"

"github.com/rickar/cal/v2"
"github.com/rickar/cal/v2/aa"
)

var (
// Standard BG weekend substitution rules:
// Saturdays move to Monday
// Sundays move to Monday
weekendAlt = []cal.AltDay{
{Day: time.Saturday, Offset: 2},
{Day: time.Sunday, Offset: 1},
}
// NewYear represents New Year's Day on 1-Jan
NewYear = aa.NewYear.Clone(&cal.Holiday{Name: "Нова година", Type: cal.ObservancePublic, Observed: weekendAlt})

// LiberationDay represents Liberation Day on 3-Mar
LiberationDay = &cal.Holiday{
Name: "Ден на Освобождението на България от османско иго - национален празник",
Type: cal.ObservancePublic,
Month: time.March,
Day: 3,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// GoodFriday represents Good Friday - two days before Easter
OrthodoxGoodFriday = &cal.Holiday{
Name: "Велики петък",
Type: cal.ObservancePublic,
Offset: -2,
Julian: true,
Func: cal.CalcEasterOffset,
}

// EasterMonday represents Easter Monday on the day after Easter
OrthodoxEasterMonday = &cal.Holiday{
Name: "Великден",
Type: cal.ObservancePublic,
Offset: 1,
Julian: true,
Func: cal.CalcEasterOffset,
}

// LabourDay represents Labour Day on 1-May
LabourDay = &cal.Holiday{
Name: "Ден на труда и на международната работническа солидарност",
Type: cal.ObservancePublic,
Month: time.May,
Day: 1,
Func: func(h *cal.Holiday, year int) time.Time {
// May 1st is quite close to OrthodoxEaster so we need to make an extra check
// If LabourDay falls on a Saturday or Sunday and Good Friday is on the Friday before that,
// then LabourDay is observed on the Tuesday after Easter.
easter := cal.CalcEasterOffset(OrthodoxGoodFriday, year)
labourDay := cal.CalcDayOfMonth(h, year)
daysDiff := labourDay.Sub(easter).Hours() / 24
if daysDiff <= 2 {
holiday := *h
holiday.Offset = 2
holiday.Julian = true
return cal.CalcEasterOffset(&holiday, year)
}
return labourDay
},
Observed: weekendAlt,
}

// StGeorgesDay represents St. George's Day on 6-May
StGeorgesDay = &cal.Holiday{
Name: "Гергьовден, Ден на храбростта и Българската армия",
Type: cal.ObservancePublic,
Month: time.May,
Day: 6,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// StCyrilAndMethodiusDay represents St. Cyril and St. Methodius Day on 24-May
StCyrilAndMethodiusDay = &cal.Holiday{
Name: "Ден на светите братя Кирил и Методий, на българската азбука, просвета и култура и на славянската книжовност",
Type: cal.ObservancePublic,
Month: time.May,
Day: 24,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// UnificationDay represents Unification Day on 6-Sep
UnificationDay = &cal.Holiday{
Name: "Ден на Съединението",
Type: cal.ObservancePublic,
Month: time.September,
Day: 6,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// IndependenceDay represents Independence Day on 22-Sep
IndependenceDay = &cal.Holiday{
Name: "Ден на Независимостта на България",
Type: cal.ObservancePublic,
Month: time.September,
Day: 22,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// ChristmasEve represents Christmas Eve 24-Dec
ChristmasEve = &cal.Holiday{
Name: "Бъдни вечер",
Type: cal.ObservancePublic,
Month: time.December,
Day: 24,
Func: cal.CalcDayOfMonth,
Observed: weekendAlt,
}

// ChristmasDay represents Christmas Day on 25-Dec
ChristmasDay = aa.ChristmasDay.Clone(&cal.Holiday{Name: "Коледа", Type: cal.ObservancePublic, Observed: []cal.AltDay{
{Day: time.Saturday, Offset: 2},
{Day: time.Sunday, Offset: 2},
}})

// ChristmasDay2 represents Christmas Day 2 on 26-Dec
ChristmasDay2 = aa.ChristmasDay2.Clone(&cal.Holiday{Name: "Коледа 2", Type: cal.ObservancePublic, Observed: []cal.AltDay{
{Day: time.Saturday, Offset: 2},
{Day: time.Sunday, Offset: 2},
{Day: time.Monday, Offset: 2},
{Day: time.Tuesday, Offset: 1}}})

// Holidays provides a list of the standard national holidays
Holidays = []*cal.Holiday{
NewYear,
LiberationDay,
OrthodoxGoodFriday,
OrthodoxEasterMonday,
LabourDay,
StGeorgesDay,
StCyrilAndMethodiusDay,
UnificationDay,
IndependenceDay,
ChristmasEve,
ChristmasDay,
ChristmasDay2,
}
)
116 changes: 116 additions & 0 deletions v2/bg/bg_holidays_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package bg

import (
"testing"
"time"

"github.com/rickar/cal/v2"
)

func d(y, m, d int) time.Time {
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, cal.DefaultLoc)
}

func TestHolidays(t *testing.T) {
tests := []struct {
h *cal.Holiday
y int
wantAct time.Time
wantObs time.Time
}{
{NewYear, 2018, d(2018, 1, 1), d(2018, 1, 1)},
{NewYear, 2019, d(2019, 1, 1), d(2019, 1, 1)},
{NewYear, 2020, d(2020, 1, 1), d(2020, 1, 1)},
{NewYear, 2021, d(2021, 1, 1), d(2021, 1, 1)},
{NewYear, 2022, d(2022, 1, 1), d(2022, 1, 3)},
{NewYear, 2023, d(2023, 1, 1), d(2023, 1, 2)},

{LiberationDay, 2018, d(2018, 3, 3), d(2018, 3, 5)},
{LiberationDay, 2019, d(2019, 3, 3), d(2019, 3, 4)},
{LiberationDay, 2020, d(2020, 3, 3), d(2020, 3, 3)},
{LiberationDay, 2021, d(2021, 3, 3), d(2021, 3, 3)},
{LiberationDay, 2022, d(2022, 3, 3), d(2022, 3, 3)},
{LiberationDay, 2023, d(2023, 3, 3), d(2023, 3, 3)},

{OrthodoxGoodFriday, 2018, d(2018, 4, 6), d(2018, 4, 6)},
{OrthodoxGoodFriday, 2019, d(2019, 4, 26), d(2019, 4, 26)},
{OrthodoxGoodFriday, 2020, d(2020, 4, 17), d(2020, 4, 17)},
{OrthodoxGoodFriday, 2021, d(2021, 4, 30), d(2021, 4, 30)},
{OrthodoxGoodFriday, 2022, d(2022, 4, 22), d(2022, 4, 22)},
{OrthodoxGoodFriday, 2023, d(2023, 4, 14), d(2023, 4, 14)},

{OrthodoxEasterMonday, 2018, d(2018, 4, 9), d(2018, 4, 9)},
{OrthodoxEasterMonday, 2019, d(2019, 4, 29), d(2019, 4, 29)},
{OrthodoxEasterMonday, 2020, d(2020, 4, 20), d(2020, 4, 20)},
{OrthodoxEasterMonday, 2021, d(2021, 5, 3), d(2021, 5, 3)},
{OrthodoxEasterMonday, 2022, d(2022, 4, 25), d(2022, 4, 25)},
{OrthodoxEasterMonday, 2023, d(2023, 4, 17), d(2023, 4, 17)},

{LabourDay, 2018, d(2018, 5, 1), d(2018, 5, 1)},
{LabourDay, 2019, d(2019, 5, 1), d(2019, 5, 1)},
{LabourDay, 2020, d(2020, 5, 1), d(2020, 5, 1)},
// Special case since OrthodoxEaster falls on that weekend
{LabourDay, 2021, d(2021, 5, 4), d(2021, 5, 4)},
{LabourDay, 2022, d(2022, 5, 1), d(2022, 5, 2)},
{LabourDay, 2023, d(2023, 5, 1), d(2023, 5, 1)},

{StGeorgesDay, 2018, d(2018, 5, 6), d(2018, 5, 7)},
{StGeorgesDay, 2019, d(2019, 5, 6), d(2019, 5, 6)},
{StGeorgesDay, 2020, d(2020, 5, 6), d(2020, 5, 6)},
{StGeorgesDay, 2021, d(2021, 5, 6), d(2021, 5, 6)},
{StGeorgesDay, 2022, d(2022, 5, 6), d(2022, 5, 6)},
{StGeorgesDay, 2023, d(2023, 5, 6), d(2023, 5, 8)},

{StCyrilAndMethodiusDay, 2018, d(2018, 5, 24), d(2018, 5, 24)},
{StCyrilAndMethodiusDay, 2019, d(2019, 5, 24), d(2019, 5, 24)},
{StCyrilAndMethodiusDay, 2020, d(2020, 5, 24), d(2020, 5, 25)},
{StCyrilAndMethodiusDay, 2021, d(2021, 5, 24), d(2021, 5, 24)},
{StCyrilAndMethodiusDay, 2022, d(2022, 5, 24), d(2022, 5, 24)},
{StCyrilAndMethodiusDay, 2023, d(2023, 5, 24), d(2023, 5, 24)},

{UnificationDay, 2018, d(2018, 9, 6), d(2018, 9, 6)},
{UnificationDay, 2019, d(2019, 9, 6), d(2019, 9, 6)},
{UnificationDay, 2020, d(2020, 9, 6), d(2020, 9, 7)},
{UnificationDay, 2021, d(2021, 9, 6), d(2021, 9, 6)},
{UnificationDay, 2022, d(2022, 9, 6), d(2022, 9, 6)},
{UnificationDay, 2023, d(2023, 9, 6), d(2023, 9, 6)},

{IndependenceDay, 2018, d(2018, 9, 22), d(2018, 9, 24)},
{IndependenceDay, 2019, d(2019, 9, 22), d(2019, 9, 23)},
{IndependenceDay, 2020, d(2020, 9, 22), d(2020, 9, 22)},
{IndependenceDay, 2021, d(2021, 9, 22), d(2021, 9, 22)},
{IndependenceDay, 2022, d(2022, 9, 22), d(2022, 9, 22)},
{IndependenceDay, 2023, d(2023, 9, 22), d(2023, 9, 22)},

{ChristmasEve, 2018, d(2018, 12, 24), d(2018, 12, 24)},
{ChristmasEve, 2019, d(2019, 12, 24), d(2019, 12, 24)},
{ChristmasEve, 2020, d(2020, 12, 24), d(2020, 12, 24)},
{ChristmasEve, 2021, d(2021, 12, 24), d(2021, 12, 24)},
{ChristmasEve, 2022, d(2022, 12, 24), d(2022, 12, 26)},
{ChristmasEve, 2023, d(2023, 12, 24), d(2023, 12, 25)},

{ChristmasDay, 2018, d(2018, 12, 25), d(2018, 12, 25)},
{ChristmasDay, 2019, d(2019, 12, 25), d(2019, 12, 25)},
{ChristmasDay, 2020, d(2020, 12, 25), d(2020, 12, 25)},
{ChristmasDay, 2021, d(2021, 12, 25), d(2021, 12, 27)},
{ChristmasDay, 2022, d(2022, 12, 25), d(2022, 12, 27)},
{ChristmasDay, 2023, d(2023, 12, 25), d(2023, 12, 25)},

{ChristmasDay2, 2018, d(2018, 12, 26), d(2018, 12, 26)},
{ChristmasDay2, 2019, d(2019, 12, 26), d(2019, 12, 26)},
{ChristmasDay2, 2020, d(2020, 12, 26), d(2020, 12, 28)},
{ChristmasDay2, 2021, d(2021, 12, 26), d(2021, 12, 28)},
{ChristmasDay2, 2022, d(2022, 12, 26), d(2022, 12, 28)},
{ChristmasDay2, 2023, d(2023, 12, 26), d(2023, 12, 27)},
}

for _, test := range tests {
gotAct, gotObs := test.h.Calc(test.y)
if !gotAct.Equal(test.wantAct) {
t.Errorf("%s %d: got actual: %s, want: %s", test.h.Name, test.y, gotAct.String(), test.wantAct.String())
}
if !gotObs.Equal(test.wantObs) {
t.Errorf("%s %d: got observed: %s, want: %s", test.h.Name, test.y, gotObs.String(), test.wantObs.String())
}
}
}

0 comments on commit 5cbae22

Please sign in to comment.