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 kr holidays #63

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
add kr holidays except lunar dates
  • Loading branch information
aanoaa committed Mar 16, 2021
commit f388f19d066c1d2df132a0ae12bc683e0b346363
111 changes: 111 additions & 0 deletions v2/kr/kr_holidays.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// (c) Rick Arnold. Licensed under the BSD license (see LICENSE).

// Package kr provides holiday definitions for the Republic of Korea.
package kr

import (
"time"

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

var (
// Standard KR weekend substitution rules:
// https://ko.wikipedia.org/wiki/%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD%EC%9D%98_%EA%B3%B5%ED%9C%B4%EC%9D%BC
// If the Lunar New Year holiday and Chuseok holiday overlap with other public holidays, including Sundays,
// the first weekday after the holiday shall be an alternative holiday, and if Children's Day overlaps with other
// public holidays or Saturdays, the first weekday shall be an alternative holiday (Article 3.[1] New November 5, 2013).

// 설날 연휴와 추석 연휴가 일요일을 포함한 다른 공휴일과 겹칠 경우에는 연휴 다음 첫번째 평일을 대체공휴일로 하고,
// 어린이날이 다른 공휴일이나 토요일과 겹칠 경우에는 그 다음 첫번째 평일을 대체공휴일로 한다.
// (관공서의 공휴일에 관한 규정 제3조.[1] 2013년 11월 5일 신설)

// Saturdays and Sundays move to next weekday

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})

// TODO: 설날 LunarNewYear
// Observed: weekendAlt,

// IndependenceMovementDay represents 3.1절 on the 1-Mar
IndependenceMovementDay = &cal.Holiday{
Name: "3.1절",
Type: cal.ObservancePublic,
Month: time.March,
Day: 1,
Func: cal.CalcDayOfMonth,
}

// ChildrensDay represents 어린이날 on the 5-May
ChildrensDay = &cal.Holiday{
Name: "어린이날",
Type: cal.ObservancePublic,
Month: time.May,
Day: 5,
Observed: weekendAlt,
Func: cal.CalcDayOfMonth,
}

// TODO: 부처님 오신 날 lunar

// MemorialDay represents 현충일 on the 6-June
MemorialDay = &cal.Holiday{
Name: "현충일",
Type: cal.ObservancePublic,
Month: time.June,
Day: 6,
Func: cal.CalcDayOfMonth,
}

// LiberationDay represents 광복절 on the 15-August
LiberationDay = &cal.Holiday{
Name: "광복절",
Type: cal.ObservancePublic,
Month: time.August,
Day: 15,
Func: cal.CalcDayOfMonth,
}

// TODO: 추석 lunar Chuseok
// Observed: weekendAlt,

// FoundationDay represents 개천절 on the 3-October
FoundationDay = &cal.Holiday{
Name: "개천절",
Type: cal.ObservancePublic,
Month: time.October,
Day: 3,
Func: cal.CalcDayOfMonth,
}

// HangeulDay represents 개천절 on the 9-October
HangeulDay = &cal.Holiday{
Name: "한글날",
Type: cal.ObservancePublic,
Month: time.October,
Day: 9,
Func: cal.CalcDayOfMonth,
}

// ChristmasDay represents 성탄절 on the 25-Dec
ChristmasDay = aa.ChristmasDay.Clone(&cal.Holiday{Name: "성탄절", Type: cal.ObservancePublic})

// Holidays provides a list of the standard national holidays
Holidays = []*cal.Holiday{
NewYear,
IndependenceMovementDay,
ChildrensDay,
MemorialDay,
LiberationDay,
FoundationDay,
HangeulDay,
ChristmasDay,
}
)
105 changes: 105 additions & 0 deletions v2/kr/kr_holidays_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// (c) Rick Arnold. Licensed under the BSD license (see LICENSE).

package kr

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, 2015, d(2015, 1, 1), d(2015, 1, 1)},
{NewYear, 2016, d(2016, 1, 1), d(2016, 1, 1)},
{NewYear, 2017, d(2017, 1, 1), d(2017, 1, 1)},
{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, 1)},

{IndependenceMovementDay, 2015, d(2015, 3, 1), d(2015, 3, 1)},
{IndependenceMovementDay, 2016, d(2016, 3, 1), d(2016, 3, 1)},
{IndependenceMovementDay, 2017, d(2017, 3, 1), d(2017, 3, 1)},
{IndependenceMovementDay, 2018, d(2018, 3, 1), d(2018, 3, 1)},
{IndependenceMovementDay, 2019, d(2019, 3, 1), d(2019, 3, 1)},
{IndependenceMovementDay, 2020, d(2020, 3, 1), d(2020, 3, 1)},
{IndependenceMovementDay, 2021, d(2021, 3, 1), d(2021, 3, 1)},
{IndependenceMovementDay, 2022, d(2022, 3, 1), d(2022, 3, 1)},

{ChildrensDay, 2015, d(2015, 5, 5), d(2015, 5, 5)},
{ChildrensDay, 2016, d(2016, 5, 5), d(2016, 5, 5)},
{ChildrensDay, 2017, d(2017, 5, 5), d(2017, 5, 5)},
{ChildrensDay, 2018, d(2018, 5, 5), d(2018, 5, 7)},
{ChildrensDay, 2019, d(2019, 5, 5), d(2019, 5, 6)},
{ChildrensDay, 2020, d(2020, 5, 5), d(2020, 5, 5)},
{ChildrensDay, 2021, d(2021, 5, 5), d(2021, 5, 5)},
{ChildrensDay, 2022, d(2022, 5, 5), d(2022, 5, 5)},

{MemorialDay, 2015, d(2015, 6, 6), d(2015, 6, 6)},
{MemorialDay, 2016, d(2016, 6, 6), d(2016, 6, 6)},
{MemorialDay, 2017, d(2017, 6, 6), d(2017, 6, 6)},
{MemorialDay, 2018, d(2018, 6, 6), d(2018, 6, 6)},
{MemorialDay, 2019, d(2019, 6, 6), d(2019, 6, 6)},
{MemorialDay, 2020, d(2020, 6, 6), d(2020, 6, 6)},
{MemorialDay, 2021, d(2021, 6, 6), d(2021, 6, 6)},
{MemorialDay, 2022, d(2022, 6, 6), d(2022, 6, 6)},

{LiberationDay, 2015, d(2015, 8, 15), d(2015, 8, 15)},
{LiberationDay, 2016, d(2016, 8, 15), d(2016, 8, 15)},
{LiberationDay, 2017, d(2017, 8, 15), d(2017, 8, 15)},
{LiberationDay, 2018, d(2018, 8, 15), d(2018, 8, 15)},
{LiberationDay, 2019, d(2019, 8, 15), d(2019, 8, 15)},
{LiberationDay, 2020, d(2020, 8, 15), d(2020, 8, 15)},
{LiberationDay, 2021, d(2021, 8, 15), d(2021, 8, 15)},
{LiberationDay, 2022, d(2022, 8, 15), d(2022, 8, 15)},

{FoundationDay, 2015, d(2015, 10, 3), d(2015, 10, 3)},
{FoundationDay, 2016, d(2016, 10, 3), d(2016, 10, 3)},
{FoundationDay, 2017, d(2017, 10, 3), d(2017, 10, 3)},
{FoundationDay, 2018, d(2018, 10, 3), d(2018, 10, 3)},
{FoundationDay, 2019, d(2019, 10, 3), d(2019, 10, 3)},
{FoundationDay, 2020, d(2020, 10, 3), d(2020, 10, 3)},
{FoundationDay, 2021, d(2021, 10, 3), d(2021, 10, 3)},
{FoundationDay, 2022, d(2022, 10, 3), d(2022, 10, 3)},

{HangeulDay, 2015, d(2015, 10, 9), d(2015, 10, 9)},
{HangeulDay, 2016, d(2016, 10, 9), d(2016, 10, 9)},
{HangeulDay, 2017, d(2017, 10, 9), d(2017, 10, 9)},
{HangeulDay, 2018, d(2018, 10, 9), d(2018, 10, 9)},
{HangeulDay, 2019, d(2019, 10, 9), d(2019, 10, 9)},
{HangeulDay, 2020, d(2020, 10, 9), d(2020, 10, 9)},
{HangeulDay, 2021, d(2021, 10, 9), d(2021, 10, 9)},
{HangeulDay, 2022, d(2022, 10, 9), d(2022, 10, 9)},

{ChristmasDay, 2015, d(2015, 12, 25), d(2015, 12, 25)},
{ChristmasDay, 2016, d(2016, 12, 25), d(2016, 12, 25)},
{ChristmasDay, 2017, d(2017, 12, 25), d(2017, 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, 25)},
{ChristmasDay, 2022, d(2022, 12, 25), d(2022, 12, 25)},
}

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())
}
}
}