mirror of
https://github.com/therootcompany/golib.git
synced 2025-11-20 05:25:38 +00:00
137 lines
5.1 KiB
Go
137 lines
5.1 KiB
Go
package calendar
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type testCase struct {
|
|
inputDate string
|
|
inputTZ string
|
|
expected string
|
|
}
|
|
|
|
func TestNthWeekday(t *testing.T) {
|
|
tests := []testCase{
|
|
{"2025-10-31T00:00:00Z", "UTC", "2025-10-31 (Fri) is the 5th Friday of the month"},
|
|
{"2025-11-01T00:00:00Z", "UTC", "2025-11-01 (Sat) is the 1st Saturday of the month"},
|
|
{"2025-11-02T00:00:00Z", "UTC", "2025-11-02 (Sun) is the 1st Sunday of the month"},
|
|
{"2025-11-06T00:00:00Z", "UTC", "2025-11-06 (Thu) is the 1st Thursday of the month"},
|
|
{"2025-11-07T00:00:00Z", "UTC", "2025-11-07 (Fri) is the 1st Friday of the month"},
|
|
{"2025-11-08T00:00:00Z", "UTC", "2025-11-08 (Sat) is the 2nd Saturday of the month"},
|
|
{"2025-10-31T00:00:00Z", "America/Denver", "2025-10-31 (Fri) is the 5th Friday of the month"},
|
|
{"2025-11-01T00:00:00Z", "America/Denver", "2025-11-01 (Sat) is the 1st Saturday of the month"},
|
|
{"2025-11-02T00:00:00Z", "America/Denver", "2025-11-02 (Sun) is the 1st Sunday of the month"},
|
|
{"2025-11-06T00:00:00Z", "America/Denver", "2025-11-06 (Thu) is the 1st Thursday of the month"},
|
|
{"2025-11-07T00:00:00Z", "America/Denver", "2025-11-07 (Fri) is the 1st Friday of the month"},
|
|
{"2025-11-08T00:00:00Z", "America/Denver", "2025-11-08 (Sat) is the 2nd Saturday of the month"},
|
|
{"2025-11-15T00:00:00Z", "UTC", "2025-11-15 (Sat) is the 3rd Saturday of the month"},
|
|
{"2025-11-30T00:00:00Z", "UTC", "2025-11-30 (Sun) is the 5th Sunday of the month"},
|
|
{"2025-02-28T00:00:00Z", "UTC", "2025-02-28 (Fri) is the 4th Friday of the month"},
|
|
{"2024-02-29T00:00:00Z", "UTC", "2024-02-29 (Thu) is the 5th Thursday of the month"},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.inputDate+"_"+tc.inputTZ, func(t *testing.T) {
|
|
loc, _ := time.LoadLocation(tc.inputTZ)
|
|
date, _ := time.ParseInLocation(time.RFC3339, tc.inputDate, loc)
|
|
|
|
nth := NthWeekday(date)
|
|
got := fmt.Sprintf("%s is the %d%s %s of the month",
|
|
date.Format("2006-01-02 (Mon)"),
|
|
nth,
|
|
GetSuffixEnglish(nth),
|
|
date.Weekday())
|
|
|
|
if got != tc.expected {
|
|
t.Errorf("expected %q, got %q", tc.expected, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type nthWeekdayTest struct {
|
|
year int
|
|
month time.Month
|
|
weekday time.Weekday
|
|
n int
|
|
wantDate string
|
|
wantOK bool
|
|
}
|
|
|
|
func TestGetNthWeekday(t *testing.T) {
|
|
tests := []nthWeekdayTest{
|
|
{2025, time.November, time.Saturday, 1, "2025-11-01", true},
|
|
{2025, time.November, time.Saturday, 2, "2025-11-08", true},
|
|
{2025, time.November, time.Saturday, 3, "2025-11-15", true},
|
|
{2025, time.November, time.Saturday, 4, "2025-11-22", true},
|
|
{2025, time.November, time.Saturday, 5, "2025-11-29", true},
|
|
{2025, time.November, time.Saturday, 6, "", false},
|
|
{2025, time.November, time.Saturday, 0, "", false},
|
|
{2025, time.November, time.Saturday, -1, "2025-11-29", true},
|
|
{2025, time.November, time.Saturday, -2, "2025-11-22", true},
|
|
{2025, time.November, time.Saturday, -3, "2025-11-15", true},
|
|
{2025, time.November, time.Saturday, -4, "2025-11-08", true},
|
|
{2025, time.November, time.Saturday, -5, "2025-11-01", true},
|
|
{2025, time.November, time.Saturday, -6, "", false},
|
|
|
|
{2025, time.November, time.Sunday, 1, "2025-11-02", true},
|
|
{2025, time.November, time.Friday, 1, "2025-11-07", true},
|
|
{2025, time.November, time.Friday, 5, "", false}, // only 4 Fridays
|
|
|
|
{2024, time.February, time.Monday, 5, "", false}, // Feb 2024 has only 4 Mondays
|
|
{2024, time.February, time.Thursday, 4, "2024-02-22", true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
name := fmt.Sprintf("%d-%02d-%s-%d", tt.year, tt.month, tt.weekday, tt.n)
|
|
t.Run(name, func(t *testing.T) {
|
|
got, ok := GetNthWeekday(tt.year, tt.month, tt.weekday, tt.n)
|
|
if ok != tt.wantOK {
|
|
t.Fatalf("ok mismatch: want %v, got %v", tt.wantOK, ok)
|
|
}
|
|
if !ok {
|
|
return
|
|
}
|
|
if got.Format("2006-01-02") != tt.wantDate {
|
|
t.Errorf("date = %s, want %s", got.Format("2006-01-02"), tt.wantDate)
|
|
}
|
|
if got.Weekday() != tt.weekday {
|
|
t.Errorf("weekday = %s, want %s", got.Weekday(), tt.weekday)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type businessDaysBeforeTest struct {
|
|
start string
|
|
n int
|
|
want string
|
|
}
|
|
|
|
func TestGetBankDaysBefore(t *testing.T) {
|
|
tests := []businessDaysBeforeTest{
|
|
{"2025-11-10T12:00:01Z", 1, "2025-11-07T12:00:01Z"}, // Mon → Fri
|
|
{"2025-11-10T12:00:02Z", 2, "2025-11-06T12:00:02Z"}, // Mon → Thu
|
|
{"2025-11-08T12:00:03Z", 1, "2025-11-06T12:00:03Z"}, // Sat (non-biz) → count 2 → Thu
|
|
{"2025-11-11T12:00:04Z", 1, "2025-11-10T12:00:04Z"}, // Wed → Tue
|
|
{"2025-11-27T12:00:04Z", 1, "2025-11-25T12:00:04Z"}, // Thu (holiday) → count 2 → Tue
|
|
{"2025-12-26T12:00:05Z", 1, "2025-12-23T12:00:05Z"}, // Fri → Tue (skip Xmas, Xmas Eve)
|
|
{"2025-12-31T12:00:06Z", 1, "2025-12-29T12:00:06Z"}, // NYE (non-biz) → count 2 → Tue
|
|
}
|
|
cal := NewMultiYearCalendar(2025, 2025, FixedHolidays, FloatingHolidays)
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.start+"_"+strconv.Itoa(tt.n), func(t *testing.T) {
|
|
start, _ := time.Parse(time.RFC3339, tt.start)
|
|
got := cal.GetNthBankDayBefore(start, tt.n)
|
|
want, _ := time.Parse(time.RFC3339, tt.want)
|
|
if !got.Equal(want) {
|
|
t.Errorf("For %d days before %s got %s, want %s", tt.n, tt.start, got.Format(time.RFC3339), want.Format(time.RFC3339))
|
|
}
|
|
})
|
|
}
|
|
}
|