From c5846f0774a1d973dd1c7464b65602eb14dde7d9 Mon Sep 17 00:00:00 2001 From: dewkul Date: Sat, 8 Jul 2023 11:14:15 +0700 Subject: [PATCH] feat: add thai holidays --- v2/th/th_holidays.go | 201 ++++++++++++++++++++++++++++++++++++++ v2/th/th_holidays_test.go | 134 +++++++++++++++++++++++++ 2 files changed, 335 insertions(+) create mode 100644 v2/th/th_holidays.go create mode 100644 v2/th/th_holidays_test.go diff --git a/v2/th/th_holidays.go b/v2/th/th_holidays.go new file mode 100644 index 0000000..c59ecd7 --- /dev/null +++ b/v2/th/th_holidays.go @@ -0,0 +1,201 @@ +// Package th provides holiday definition for Thailand. +package th + +import ( + "time" + + "github.com/rickar/cal/v2" + "github.com/rickar/cal/v2/aa" +) + +var ( + // Standard weekend substitution rules: + // Saturdays move to Monday + // Sundays move to Monday + + weekendAlt = []cal.AltDay{ + {Day: time.Saturday, Offset: 2}, + {Day: time.Sunday, Offset: 1}, + } + + // Long weekend substitution rules: + // Saturdays move to Monday + // Sundays move to Tuesday + + longWeekendAlt = []cal.AltDay{ + {Day: time.Saturday, Offset: 2}, + {Day: time.Sunday, Offset: 2}, + } + + // NewYear represents New Year's Day on 1 Jan + NewYear = aa.NewYear.Clone(&cal.Holiday{ + Name: "วันขึ้นปีใหม่", + Type: cal.ObservancePublic, + Observed: weekendAlt, + }) + + // ChakriDay represents Chakri Dynasty Memorial Day on 6 Apr + ChakriDay = &cal.Holiday{ + Name: "วันจักรี", + Type: cal.ObservancePublic, + Month: time.April, + Day: 6, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // ElderlyDay represents Songkran and Elderly National Day on 13 Apr + ElderlyDay = &cal.Holiday{ + Name: "วันมหาสงกรานต์ / วันผู้สูงอายุ", + Type: cal.ObservancePublic, + Month: time.April, + Day: 13, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // FamilyDay represents Songkran and Family National Day on 14 Apr + FamilyDay = &cal.Holiday{ + Name: "วันสงกรานต์ / วันครอบครัวไทย", + Type: cal.ObservancePublic, + Month: time.April, + Day: 14, + Observed: longWeekendAlt, + Func: cal.CalcDayOfMonth, + } + + // ThaiNewYear represents Songkran on 15 Apr + ThaiNewYear = &cal.Holiday{ + Name: "วันสงกรานต์", + Type: cal.ObservancePublic, + Month: time.April, + Day: 15, + Observed: longWeekendAlt, + Func: cal.CalcDayOfMonth, + } + + // Songkran is held from 13 Apr to 15 Apr + SongKranDays = []*cal.Holiday{ + ElderlyDay, + FamilyDay, + ThaiNewYear, + } + + // LaborDay represents international worker's day on 1 May + LaborDay = aa.WorkersDay.Clone( + &cal.Holiday{ + Name: "วันแรงงาน", + Type: cal.ObservanceBank, + Observed: weekendAlt, + }, + ) + + // CoronationDay represents King Rama X's Coronation Day on 4 May + CoronationDay = &cal.Holiday{ + Name: "วันฉัตรมงคล", + Type: cal.ObservancePublic, + Month: time.May, + Day: 4, + StartYear: 2019, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // QueensBirthday represents Queen Suthida's birthday on 3 June + QueensBirthday = &cal.Holiday{ + Name: "วันเฉลิมพระชนมพรรษาสมเด็จพระนางเจ้าฯ พระบรมราชินี", + Type: cal.ObservancePublic, + Month: time.June, + Day: 3, + StartYear: 2019, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // KingsBirthday represents King Rama X's birthday on 28 July + KingsBirthday = &cal.Holiday{ + Name: "วันเฉลิมพระชนมพรรษาพระบาทสมเด็จพระเจ้าอยู่หัว", + Type: cal.ObservancePublic, + Month: time.July, + Day: 28, + StartYear: 2017, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // MothersDay represents Mother National Day on 12 Aug + MothersDay = &cal.Holiday{ + Name: "วันแม่แห่งชาติ", + Type: cal.ObservancePublic, + Month: time.August, + Day: 12, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // KingBhumibolDay represents King Bhumibol Memorial Day on 13 Oct + KingBhumibolDay = &cal.Holiday{ + Name: "วันคล้ายวันสวรรคต พระบาทสมเด็จพระปรมินทรมหาภูมิพลอดุลยเดชมหาราช", + Type: cal.ObservancePublic, + Month: time.October, + Day: 13, + Observed: weekendAlt, + StartYear: 2017, + Func: cal.CalcDayOfMonth, + } + + // KingChulalongkornDay represents King Chulalongkorn Memorial Day on 23 Oct + KingChulalongkornDay = &cal.Holiday{ + Name: "วันปิยมหาราช", + Type: cal.ObservancePublic, + Month: time.October, + Day: 23, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // FathersDay represents Father's National Day on 5 Dec + FathersDay = &cal.Holiday{ + Name: "วันพ่อแห่งชาติ", + Type: cal.ObservancePublic, + Month: time.December, + Day: 5, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // ConstitutionDay represents Constitution Day on 10 Dec + ConstitutionDay = &cal.Holiday{ + Name: "วันรัฐธรรมนูญ", + Type: cal.ObservancePublic, + Month: time.December, + Day: 10, + Observed: weekendAlt, + Func: cal.CalcDayOfMonth, + } + + // NewYearEve represents NewYear Eve on 31 Dec + NewYearEve = &cal.Holiday{ + Name: "วันสิ้นปี", + Type: cal.ObservancePublic, + Month: time.December, + Day: 31, + Func: cal.CalcDayOfMonth, + } + + // Holidays provides a list of the standard national holidays + holidays = []*cal.Holiday{ + NewYear, + ChakriDay, + CoronationDay, + QueensBirthday, + KingsBirthday, + MothersDay, + KingBhumibolDay, + KingChulalongkornDay, + FathersDay, + ConstitutionDay, + NewYearEve, + } + Holidays = append(holidays, SongKranDays...) +) diff --git a/v2/th/th_holidays_test.go b/v2/th/th_holidays_test.go new file mode 100644 index 0000000..0c5c7dd --- /dev/null +++ b/v2/th/th_holidays_test.go @@ -0,0 +1,134 @@ +package th + +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, 2017, d(2017, 1, 1), d(2017, 1, 2)}, + {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)}, + {ChakriDay, 2017, d(2017, 4, 6), d(2017, 4, 6)}, + {ChakriDay, 2018, d(2018, 4, 6), d(2018, 4, 6)}, + {ChakriDay, 2019, d(2019, 4, 6), d(2019, 4, 8)}, + {ChakriDay, 2020, d(2020, 4, 6), d(2020, 4, 6)}, + {ChakriDay, 2021, d(2021, 4, 6), d(2021, 4, 6)}, + {ChakriDay, 2022, d(2022, 4, 6), d(2022, 4, 6)}, + {ChakriDay, 2023, d(2023, 4, 6), d(2023, 4, 6)}, + {ElderlyDay, 2017, d(2017, 4, 13), d(2017, 4, 13)}, + {ElderlyDay, 2018, d(2018, 4, 13), d(2018, 4, 13)}, + {ElderlyDay, 2019, d(2019, 4, 13), d(2019, 4, 15)}, + {ElderlyDay, 2020, d(2020, 4, 13), d(2020, 4, 13)}, + {ElderlyDay, 2021, d(2021, 4, 13), d(2021, 4, 13)}, + {ElderlyDay, 2022, d(2022, 4, 13), d(2022, 4, 13)}, + {ElderlyDay, 2023, d(2023, 4, 13), d(2023, 4, 13)}, + {FamilyDay, 2017, d(2017, 4, 14), d(2017, 4, 14)}, + {FamilyDay, 2018, d(2018, 4, 14), d(2018, 4, 16)}, + {FamilyDay, 2019, d(2019, 4, 14), d(2019, 4, 16)}, + {FamilyDay, 2020, d(2020, 4, 14), d(2020, 4, 14)}, + {FamilyDay, 2021, d(2021, 4, 14), d(2021, 4, 14)}, + {FamilyDay, 2022, d(2022, 4, 14), d(2022, 4, 14)}, + {FamilyDay, 2023, d(2023, 4, 14), d(2023, 4, 14)}, + {ThaiNewYear, 2017, d(2017, 4, 15), d(2017, 4, 17)}, + {ThaiNewYear, 2018, d(2018, 4, 15), d(2018, 4, 17)}, + {ThaiNewYear, 2019, d(2019, 4, 15), d(2019, 4, 15)}, + {ThaiNewYear, 2020, d(2020, 4, 15), d(2020, 4, 15)}, + {ThaiNewYear, 2021, d(2021, 4, 15), d(2021, 4, 15)}, + {ThaiNewYear, 2022, d(2022, 4, 15), d(2022, 4, 15)}, + {ThaiNewYear, 2023, d(2023, 4, 15), d(2023, 4, 17)}, + {LaborDay, 2017, d(2017, 5, 1), d(2017, 5, 1)}, + {LaborDay, 2018, d(2018, 5, 1), d(2018, 5, 1)}, + {LaborDay, 2019, d(2019, 5, 1), d(2019, 5, 1)}, + {LaborDay, 2020, d(2020, 5, 1), d(2020, 5, 1)}, + {LaborDay, 2021, d(2021, 5, 1), d(2021, 5, 3)}, + {LaborDay, 2022, d(2022, 5, 1), d(2022, 5, 2)}, + {LaborDay, 2023, d(2023, 5, 1), d(2023, 5, 1)}, + {CoronationDay, 2019, d(2019, 5, 4), d(2019, 5, 6)}, + {CoronationDay, 2020, d(2020, 5, 4), d(2020, 5, 4)}, + {CoronationDay, 2021, d(2021, 5, 4), d(2021, 5, 4)}, + {CoronationDay, 2022, d(2022, 5, 4), d(2022, 5, 4)}, + {CoronationDay, 2023, d(2023, 5, 4), d(2023, 5, 4)}, + {QueensBirthday, 2019, d(2019, 6, 3), d(2019, 6, 3)}, + {QueensBirthday, 2020, d(2020, 6, 3), d(2020, 6, 3)}, + {QueensBirthday, 2021, d(2021, 6, 3), d(2021, 6, 3)}, + {QueensBirthday, 2022, d(2022, 6, 3), d(2022, 6, 3)}, + {QueensBirthday, 2023, d(2023, 6, 3), d(2023, 6, 5)}, + {KingsBirthday, 2017, d(2017, 7, 28), d(2017, 7, 28)}, + {KingsBirthday, 2018, d(2018, 7, 28), d(2018, 7, 30)}, + {KingsBirthday, 2019, d(2019, 7, 28), d(2019, 7, 29)}, + {KingsBirthday, 2020, d(2020, 7, 28), d(2020, 7, 28)}, + {KingsBirthday, 2021, d(2021, 7, 28), d(2021, 7, 28)}, + {KingsBirthday, 2022, d(2022, 7, 28), d(2022, 7, 28)}, + {KingsBirthday, 2023, d(2023, 7, 28), d(2023, 7, 28)}, + {MothersDay, 2017, d(2017, 8, 12), d(2017, 8, 14)}, + {MothersDay, 2018, d(2018, 8, 12), d(2018, 8, 13)}, + {MothersDay, 2019, d(2019, 8, 12), d(2019, 8, 12)}, + {MothersDay, 2020, d(2020, 8, 12), d(2020, 8, 12)}, + {MothersDay, 2021, d(2021, 8, 12), d(2021, 8, 12)}, + {MothersDay, 2022, d(2022, 8, 12), d(2022, 8, 12)}, + {MothersDay, 2023, d(2023, 8, 12), d(2023, 8, 14)}, + {KingBhumibolDay, 2017, d(2017, 10, 13), d(2017, 10, 13)}, + {KingBhumibolDay, 2018, d(2018, 10, 13), d(2018, 10, 15)}, + {KingBhumibolDay, 2019, d(2019, 10, 13), d(2019, 10, 14)}, + {KingBhumibolDay, 2020, d(2020, 10, 13), d(2020, 10, 13)}, + {KingBhumibolDay, 2021, d(2021, 10, 13), d(2021, 10, 13)}, + {KingBhumibolDay, 2022, d(2022, 10, 13), d(2022, 10, 13)}, + {KingBhumibolDay, 2023, d(2023, 10, 13), d(2023, 10, 13)}, + {KingChulalongkornDay, 2017, d(2017, 10, 23), d(2017, 10, 23)}, + {KingChulalongkornDay, 2018, d(2018, 10, 23), d(2018, 10, 23)}, + {KingChulalongkornDay, 2019, d(2019, 10, 23), d(2019, 10, 23)}, + {KingChulalongkornDay, 2020, d(2020, 10, 23), d(2020, 10, 23)}, + {KingChulalongkornDay, 2021, d(2021, 10, 23), d(2021, 10, 25)}, + {KingChulalongkornDay, 2022, d(2022, 10, 23), d(2022, 10, 24)}, + {KingChulalongkornDay, 2023, d(2023, 10, 23), d(2023, 10, 23)}, + {FathersDay, 2017, d(2017, 12, 5), d(2017, 12, 5)}, + {FathersDay, 2018, d(2018, 12, 5), d(2018, 12, 5)}, + {FathersDay, 2019, d(2019, 12, 5), d(2019, 12, 5)}, + {FathersDay, 2020, d(2020, 12, 5), d(2020, 12, 7)}, + {FathersDay, 2021, d(2021, 12, 5), d(2021, 12, 6)}, + {FathersDay, 2022, d(2022, 12, 5), d(2022, 12, 5)}, + {FathersDay, 2023, d(2023, 12, 5), d(2023, 12, 5)}, + {ConstitutionDay, 2017, d(2017, 12, 10), d(2017, 12, 11)}, + {ConstitutionDay, 2018, d(2018, 12, 10), d(2018, 12, 10)}, + {ConstitutionDay, 2019, d(2019, 12, 10), d(2019, 12, 10)}, + {ConstitutionDay, 2020, d(2020, 12, 10), d(2020, 12, 10)}, + {ConstitutionDay, 2021, d(2021, 12, 10), d(2021, 12, 10)}, + {ConstitutionDay, 2022, d(2022, 12, 10), d(2022, 12, 12)}, + {ConstitutionDay, 2023, d(2023, 12, 10), d(2023, 12, 11)}, + {NewYearEve, 2017, d(2017, 12, 31), d(2017, 12, 31)}, + {NewYearEve, 2018, d(2018, 12, 31), d(2018, 12, 31)}, + {NewYearEve, 2019, d(2019, 12, 31), d(2019, 12, 31)}, + {NewYearEve, 2020, d(2020, 12, 31), d(2020, 12, 31)}, + {NewYearEve, 2021, d(2021, 12, 31), d(2021, 12, 31)}, + {NewYearEve, 2022, d(2022, 12, 31), d(2022, 12, 31)}, + {NewYearEve, 2023, d(2023, 12, 31), d(2023, 12, 31)}, + } + + 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()) + } + } + +}