From bfa2306268daee3fe429dfd0edec98262832ba68 Mon Sep 17 00:00:00 2001 From: Alpa-1 <87192725+Alpa-1@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:58:51 +0100 Subject: [PATCH] feat: Add holidays for Serbia --- v2/rs/rs_holidays.go | 115 ++++++++++++++++++++++++++++++++++++++ v2/rs/rs_holidays_test.go | 77 +++++++++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 v2/rs/rs_holidays.go create mode 100644 v2/rs/rs_holidays_test.go diff --git a/v2/rs/rs_holidays.go b/v2/rs/rs_holidays.go new file mode 100644 index 0000000..5294b3f --- /dev/null +++ b/v2/rs/rs_holidays.go @@ -0,0 +1,115 @@ +// (c) Rick Arnold. Licensed under the BSD license (see LICENSE). + +// Package rs provides holiday definitions for Serbia. +package rs + +import ( + "time" + + "github.com/rickar/cal/v2" + "github.com/rickar/cal/v2/aa" +) + +var ( + // NovaGodina represents New Year's Day on 1-Jan + NovaGodina = aa.NewYear.Clone(&cal.Holiday{Name: "Nova godina", Type: cal.ObservancePublic}) + + // DrugiDanNoveGodine represents the second day of New Year's on 2-Jan + DrugiDanNoveGodine = &cal.Holiday{ + Name: "Drugi dan Nove godine", + Type: cal.ObservancePublic, + Month: time.January, + Day: 2, + Func: cal.CalcDayOfMonth, + } + + // Bozic represents Orthodox Christmas Day on 7-Jan (Julian calendar) + Bozic = &cal.Holiday{ + Name: "Božić", + Type: cal.ObservancePublic, + Month: time.January, + Day: 7, + Julian: true, + Func: cal.CalcDayOfMonth, + } + + // DanDrzavnosti represents Statehood Day on 15-Feb + DanDrzavnosti = &cal.Holiday{ + Name: "Dan državnosti", + Type: cal.ObservancePublic, + Month: time.February, + Day: 15, + Func: cal.CalcDayOfMonth, + } + + // DrugiDanDrzavnosti represents the second day of Statehood Day on 16-Feb + DrugiDanDrzavnosti = &cal.Holiday{ + Name: "Drugi dan Dana državnosti", + Type: cal.ObservancePublic, + Month: time.February, + Day: 16, + Func: cal.CalcDayOfMonth, + } + + // PraznikRada represents Labour Day on 1-May + PraznikRada = aa.WorkersDay.Clone(&cal.Holiday{Name: "Praznik rada", Type: cal.ObservancePublic}) + + // DrugiDanPraznikaRada represents the second day of Labour Day on 2-May + DrugiDanPraznikaRada = &cal.Holiday{ + Name: "Drugi dan Praznika rada", + Type: cal.ObservancePublic, + Month: time.May, + Day: 2, + Func: cal.CalcDayOfMonth, + } + + // VelikiPetak represents Orthodox Good Friday (movable, 2 days before Orthodox Easter) + VelikiPetak = &cal.Holiday{ + Name: "Veliki petak", + Type: cal.ObservancePublic, + Func: cal.CalcEasterOffset, + Julian: true, + Offset: -2, + } + + // Vaskrs represents Orthodox Easter Sunday (movable) + Vaskrs = &cal.Holiday{ + Name: "Vaskrs", + Type: cal.ObservancePublic, + Func: cal.CalcEasterOffset, + Julian: true, + } + + // VaskrsnjiPonedeljak represents Orthodox Easter Monday (movable, 1 day after Orthodox Easter) + VaskrsnjiPonedeljak = &cal.Holiday{ + Name: "Vaskršnji ponedeljak", + Type: cal.ObservancePublic, + Func: cal.CalcEasterOffset, + Julian: true, + Offset: 1, + } + + // DanPrimirja represents Armistice Day on 11-Nov + DanPrimirja = &cal.Holiday{ + Name: "Dan primirja u Prvom svetskom ratu", + Type: cal.ObservancePublic, + Month: time.November, + Day: 11, + Func: cal.CalcDayOfMonth, + } + + // Holidays provides a list of the standard national holidays + Holidays = []*cal.Holiday{ + NovaGodina, + DrugiDanNoveGodine, + Bozic, + DanDrzavnosti, + DrugiDanDrzavnosti, + PraznikRada, + DrugiDanPraznikaRada, + VelikiPetak, + Vaskrs, + VaskrsnjiPonedeljak, + DanPrimirja, + } +) diff --git a/v2/rs/rs_holidays_test.go b/v2/rs/rs_holidays_test.go new file mode 100644 index 0000000..7149d86 --- /dev/null +++ b/v2/rs/rs_holidays_test.go @@ -0,0 +1,77 @@ +// (c) Rick Arnold. Licensed under the BSD license (see LICENSE). + +package rs + +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 + }{ + {NovaGodina, 2024, d(2024, 1, 1), d(2024, 1, 1)}, + {NovaGodina, 2025, d(2025, 1, 1), d(2025, 1, 1)}, + {NovaGodina, 2026, d(2026, 1, 1), d(2026, 1, 1)}, + + {DrugiDanNoveGodine, 2024, d(2024, 1, 2), d(2024, 1, 2)}, + {DrugiDanNoveGodine, 2025, d(2025, 1, 2), d(2025, 1, 2)}, + {DrugiDanNoveGodine, 2026, d(2026, 1, 2), d(2026, 1, 2)}, + + {Bozic, 2024, d(2024, 1, 7), d(2024, 1, 7)}, + {Bozic, 2025, d(2025, 1, 7), d(2025, 1, 7)}, + {Bozic, 2026, d(2026, 1, 7), d(2026, 1, 7)}, + + {DanDrzavnosti, 2024, d(2024, 2, 15), d(2024, 2, 15)}, + {DanDrzavnosti, 2025, d(2025, 2, 15), d(2025, 2, 15)}, + {DanDrzavnosti, 2026, d(2026, 2, 15), d(2026, 2, 15)}, + + {DrugiDanDrzavnosti, 2024, d(2024, 2, 16), d(2024, 2, 16)}, + {DrugiDanDrzavnosti, 2025, d(2025, 2, 16), d(2025, 2, 16)}, + {DrugiDanDrzavnosti, 2026, d(2026, 2, 16), d(2026, 2, 16)}, + + {PraznikRada, 2024, d(2024, 5, 1), d(2024, 5, 1)}, + {PraznikRada, 2025, d(2025, 5, 1), d(2025, 5, 1)}, + {PraznikRada, 2026, d(2026, 5, 1), d(2026, 5, 1)}, + + {DrugiDanPraznikaRada, 2024, d(2024, 5, 2), d(2024, 5, 2)}, + {DrugiDanPraznikaRada, 2025, d(2025, 5, 2), d(2025, 5, 2)}, + {DrugiDanPraznikaRada, 2026, d(2026, 5, 2), d(2026, 5, 2)}, + + {VelikiPetak, 2024, d(2024, 5, 3), d(2024, 5, 3)}, + {VelikiPetak, 2025, d(2025, 4, 18), d(2025, 4, 18)}, + {VelikiPetak, 2026, d(2026, 4, 10), d(2026, 4, 10)}, + + {Vaskrs, 2024, d(2024, 5, 5), d(2024, 5, 5)}, + {Vaskrs, 2025, d(2025, 4, 20), d(2025, 4, 20)}, + {Vaskrs, 2026, d(2026, 4, 12), d(2026, 4, 12)}, + + {VaskrsnjiPonedeljak, 2024, d(2024, 5, 6), d(2024, 5, 6)}, + {VaskrsnjiPonedeljak, 2025, d(2025, 4, 21), d(2025, 4, 21)}, + {VaskrsnjiPonedeljak, 2026, d(2026, 4, 13), d(2026, 4, 13)}, + + {DanPrimirja, 2024, d(2024, 11, 11), d(2024, 11, 11)}, + {DanPrimirja, 2025, d(2025, 11, 11), d(2025, 11, 11)}, + {DanPrimirja, 2026, d(2026, 11, 11), d(2026, 11, 11)}, + } + + 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()) + } + } +}