-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathzone.go
90 lines (81 loc) · 2 KB
/
zone.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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
}