91 lines
2.0 KiB
Go
91 lines
2.0 KiB
Go
package main
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/serverwentdown/datetime.link/data"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Zone represents any form of zone offset: this could be a city or a fixed
|
|
// offset from UTC
|
|
type Zone struct {
|
|
// City is optional
|
|
City *data.City
|
|
// Offset is optional
|
|
Offset *time.Location
|
|
}
|
|
|
|
// IsOffset is true when the Zone is an offset instead of a city
|
|
func (z Zone) IsOffset() bool {
|
|
return z.Offset != nil
|
|
}
|
|
|
|
// Name returns the name of the zone
|
|
func (z Zone) Name() string {
|
|
if z.IsOffset() {
|
|
return z.Offset.String()
|
|
} else if z.City != nil {
|
|
return z.City.FullName()
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// FirstName returns the primary name of the zone
|
|
func (z Zone) FirstName() string {
|
|
if z.IsOffset() {
|
|
return z.Offset.String()
|
|
} else if z.City != nil {
|
|
if len(z.City.Admin1.Name) > 0 {
|
|
return z.City.Name + ", " + z.City.Admin1.Name
|
|
}
|
|
return z.City.Name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// Location returns the time.Location of the zone. Useful for other functions
|
|
func (z Zone) Location() *time.Location {
|
|
if z.IsOffset() {
|
|
return z.Offset
|
|
} else if z.City != nil {
|
|
loc, err := time.LoadLocation(z.City.Timezone)
|
|
if err != nil {
|
|
// This is a really bad situation
|
|
// TODO: validate this at boot time
|
|
l.Error("unable to find timezone", zap.String("timezone", z.City.Timezone))
|
|
}
|
|
return loc
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// TimeOffset returns the timezone offset at a specific time
|
|
func (z Zone) TimeOffset(t time.Time) int {
|
|
if l := z.Location(); l != nil {
|
|
_, offset := t.In(l).Zone()
|
|
return offset
|
|
}
|
|
return -1 // TODO: better invalid handling
|
|
}
|
|
|
|
// ResolveZone resolves a zone string into a Zone
|
|
func ResolveZone(cities map[string]*data.City, zone string) (Zone, error) {
|
|
// Try parsing as a zone offset
|
|
offset, err := ParseZoneOffset(zone)
|
|
if err == nil {
|
|
offsetZone := time.FixedZone("UTC "+FormatZoneOffset(offset), offset)
|
|
return Zone{
|
|
Offset: offsetZone,
|
|
}, nil
|
|
}
|
|
// Parse as a city
|
|
city, err := SearchCities(cities, zone)
|
|
if err == nil {
|
|
return Zone{
|
|
City: city,
|
|
}, nil
|
|
}
|
|
return Zone{}, err
|
|
}
|