2016-09-23 13:31:26 +00:00
|
|
|
package holidays
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"sort"
|
|
|
|
"time"
|
2016-11-29 00:02:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const day = 24 * time.Hour
|
2016-09-23 13:31:26 +00:00
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
var (
|
|
|
|
HolidayDataNotFoundError = errors.New("Holiday data not found for requested country-code")
|
|
|
|
holidayProviders = map[string]holidayDataSource{}
|
2016-09-23 13:31:26 +00:00
|
|
|
)
|
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
func registerHolidayDataSource(code string, hds holidayDataSource) {
|
|
|
|
if _, ok := holidayProviders[code]; ok {
|
|
|
|
panic(fmt.Errorf("Duplicatei definition for country code %q", code))
|
|
|
|
}
|
|
|
|
|
|
|
|
holidayProviders[code] = hds
|
|
|
|
}
|
2016-09-23 13:31:26 +00:00
|
|
|
|
|
|
|
// Holiday contains information about an holiday
|
|
|
|
type Holiday struct {
|
|
|
|
// Name contains the english representation of the holidays name
|
2016-09-24 12:19:01 +00:00
|
|
|
Name string `json:"name"`
|
2016-09-23 13:31:26 +00:00
|
|
|
// LocalizedName contains a map of localizations of the name, key is a ISO 3166-2 country code without subdivision
|
2016-09-24 12:19:01 +00:00
|
|
|
LocalizedName map[string]string `json:"localized_name"`
|
|
|
|
// Date contains the date in YYYY-MM-DD notation
|
|
|
|
Date string `json:"date"`
|
2016-11-29 00:02:36 +00:00
|
|
|
// ParsedDate is the Date as a time.Time object
|
|
|
|
ParsedDate time.Time `json:"parsed_date"`
|
2016-09-23 13:31:26 +00:00
|
|
|
}
|
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
func newHoliday(name string, localizedName map[string]string, parsedDate time.Time) Holiday {
|
|
|
|
return Holiday{
|
|
|
|
Name: name,
|
|
|
|
LocalizedName: localizedName,
|
|
|
|
Date: parsedDate.Format("2006-01-02"),
|
|
|
|
ParsedDate: parsedDate,
|
|
|
|
}
|
|
|
|
}
|
2016-09-23 13:31:26 +00:00
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
func dateFromNumbers(year, month, day int) time.Time {
|
|
|
|
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
|
|
|
|
}
|
|
|
|
|
|
|
|
type holidayDataSource interface {
|
|
|
|
GetIncludes() []string
|
|
|
|
GetHolidays(year int) []Holiday
|
|
|
|
}
|
2016-09-23 13:31:26 +00:00
|
|
|
|
|
|
|
// GetHolidays returns the holidays for the given ISO 3166-2 countryCode and year
|
|
|
|
func GetHolidays(countryCode string, year int) ([]Holiday, error) {
|
2016-11-29 00:02:36 +00:00
|
|
|
requiredCodes := []string{countryCode}
|
2016-09-23 13:31:26 +00:00
|
|
|
result := []Holiday{}
|
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
for len(requiredCodes) > 0 {
|
|
|
|
cc := requiredCodes[0]
|
|
|
|
hds, ok := holidayProviders[cc]
|
|
|
|
if !ok {
|
|
|
|
return nil, HolidayDataNotFoundError
|
2016-09-23 13:31:26 +00:00
|
|
|
}
|
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
requiredCodes = append(requiredCodes, hds.GetIncludes()...)
|
|
|
|
result = append(result, hds.GetHolidays(year)...)
|
2016-09-23 13:31:26 +00:00
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
requiredCodes = requiredCodes[1:]
|
2016-09-23 13:31:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(holidays(result))
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
type holidays []Holiday
|
2016-09-23 13:31:26 +00:00
|
|
|
|
2016-11-29 00:02:36 +00:00
|
|
|
func (h holidays) Len() int { return len(h) }
|
|
|
|
func (h holidays) Less(i, j int) bool { return h[i].Date < h[j].Date }
|
|
|
|
func (h holidays) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|