Files

93 lines
2.4 KiB
Go

package timeutil
import (
"fmt"
"regexp"
"strconv"
"strings"
"time"
)
const DateLayout = "2006-01-02"
const LocalDateTimeLayout = "2006-01-02T15:04"
func LoadLocation(name string) (*time.Location, error) {
if location, ok := timezoneAliases[name]; ok {
return location, nil
}
if location, ok := parseUTCOffset(name); ok {
return location, nil
}
location, err := time.LoadLocation(name)
if err == nil {
return location, nil
}
if strings.Contains(name, "/") {
return nil, fmt.Errorf("load timezone %q: %w", name, err)
}
location, chicagoErr := time.LoadLocation("America/" + name)
if chicagoErr == nil {
return location, nil
}
return nil, fmt.Errorf("load timezone %q: %w", name, err)
}
var timezoneAliases = map[string]*time.Location{
"Chicago": mustLocation("America/Chicago"),
"Stl": mustLocation("America/Chicago"),
"EST": time.FixedZone("EST", -5*60*60),
"EDT": time.FixedZone("EDT", -4*60*60),
"CST": time.FixedZone("CST", -6*60*60),
"CDT": time.FixedZone("CDT", -5*60*60),
"MST": time.FixedZone("MST", -7*60*60),
"MDT": time.FixedZone("MDT", -6*60*60),
"PST": time.FixedZone("PST", -8*60*60),
"PDT": time.FixedZone("PDT", -7*60*60),
}
func mustLocation(name string) *time.Location {
location, err := time.LoadLocation(name)
if err != nil {
panic(err)
}
return location
}
var utcOffsetPattern = regexp.MustCompile(`^([+-])(\d{1,2})(?::?(\d{2}))?$`)
func parseUTCOffset(value string) (*time.Location, bool) {
matches := utcOffsetPattern.FindStringSubmatch(value)
if matches == nil {
return nil, false
}
hours, err := strconv.Atoi(matches[2])
if err != nil || hours > 23 {
return nil, false
}
minutes := 0
if matches[3] != "" {
minutes, err = strconv.Atoi(matches[3])
if err != nil || minutes > 59 {
return nil, false
}
}
offset := (hours*60 + minutes) * 60
if matches[1] == "-" {
offset = -offset
}
return time.FixedZone(value, offset), true
}
func LocalDate(now time.Time, location *time.Location) time.Time {
local := now.In(location)
return time.Date(local.Year(), local.Month(), local.Day(), 0, 0, 0, 0, location)
}
func ParseLocalDate(value string, location *time.Location) (time.Time, error) {
parsed, err := time.ParseInLocation(DateLayout, value, location)
if err != nil {
return time.Time{}, fmt.Errorf("parse date %q as YYYY-MM-DD: %w", value, err)
}
return parsed, nil
}