mirror of
https://github.com/warmbly/warmbly.git
synced 2026-08-19 08:01:16 +00:00
141 lines
2.5 KiB
Go
141 lines
2.5 KiB
Go
package tz
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"sort"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
var tzs = []string{
|
|
"America/New_York",
|
|
"America/Chicago",
|
|
"America/Denver",
|
|
"America/Los_Angeles",
|
|
"America/Toronto",
|
|
"America/Sao_Paulo",
|
|
"America/Mexico_City",
|
|
"America/Bogota",
|
|
"America/Lima",
|
|
"America/Caracas",
|
|
"America/Argentina/Buenos_Aires",
|
|
"America/Anchorage",
|
|
"America/Phoenix",
|
|
"America/Winnipeg",
|
|
"America/Montevideo",
|
|
|
|
"Europe/London",
|
|
"Europe/Paris",
|
|
"Europe/Berlin",
|
|
"Europe/Madrid",
|
|
"Europe/Rome",
|
|
"Europe/Moscow",
|
|
"Europe/Istanbul",
|
|
"Europe/Budapest",
|
|
"Europe/Amsterdam",
|
|
"Europe/Stockholm",
|
|
"Europe/Vienna",
|
|
"Europe/Zurich",
|
|
|
|
"Africa/Johannesburg",
|
|
"Africa/Cairo",
|
|
"Africa/Lagos",
|
|
"Africa/Nairobi",
|
|
|
|
"Asia/Dubai",
|
|
"Asia/Kolkata",
|
|
"Asia/Bangkok",
|
|
"Asia/Shanghai",
|
|
"Asia/Hong_Kong",
|
|
"Asia/Tokyo",
|
|
"Asia/Seoul",
|
|
"Asia/Tehran",
|
|
"Asia/Jerusalem",
|
|
"Asia/Karachi",
|
|
"Asia/Dhaka",
|
|
"Asia/Singapore",
|
|
"Asia/Taipei",
|
|
|
|
"Australia/Sydney",
|
|
"Australia/Melbourne",
|
|
"Australia/Brisbane",
|
|
"Pacific/Auckland",
|
|
"Pacific/Honolulu",
|
|
"Pacific/Fiji",
|
|
}
|
|
|
|
type TimezoneOption struct {
|
|
Name string `json:"name"` // IANA name, ex. "Europe/Budapest"
|
|
DisplayName string `json:"display_name"` // ex. "(UTC+02:00) Budapest"
|
|
}
|
|
|
|
type Client struct {
|
|
sync.RWMutex
|
|
lastFetched time.Time
|
|
Timezones []TimezoneOption
|
|
}
|
|
|
|
func Valid(name string) bool {
|
|
return slices.Contains(tzs, name)
|
|
}
|
|
|
|
func NewTZ() *Client {
|
|
fetchTimes()
|
|
tz := &Client{}
|
|
tz.fetch()
|
|
return tz
|
|
}
|
|
|
|
func (t *Client) Get() []TimezoneOption {
|
|
t.RLock()
|
|
|
|
if time.Since(t.lastFetched) > 24*time.Hour {
|
|
t.RUnlock()
|
|
t.Lock()
|
|
t.fetch()
|
|
t.Unlock()
|
|
t.RLock()
|
|
}
|
|
defer t.RUnlock()
|
|
return t.Timezones
|
|
}
|
|
|
|
func (t *Client) fetch() {
|
|
now := time.Now()
|
|
|
|
sort.Slice(tzs, func(i, j int) bool {
|
|
locI, _ := time.LoadLocation(tzs[i])
|
|
locJ, _ := time.LoadLocation(tzs[j])
|
|
_, offsetI := now.In(locI).Zone()
|
|
_, offsetJ := now.In(locJ).Zone()
|
|
return offsetI < offsetJ
|
|
})
|
|
|
|
options := make([]TimezoneOption, 0, len(tzs))
|
|
|
|
for _, tz := range tzs {
|
|
loc, err := time.LoadLocation(tz)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
_, offsetSeconds := now.In(loc).Zone()
|
|
|
|
sign := "+"
|
|
if offsetSeconds < 0 {
|
|
sign = "-"
|
|
offsetSeconds = -offsetSeconds
|
|
}
|
|
hours := offsetSeconds / 3600
|
|
minutes := (offsetSeconds % 3600) / 60
|
|
|
|
display := fmt.Sprintf("(UTC%s%02d:%02d) %s", sign, hours, minutes, tz)
|
|
options = append(options, TimezoneOption{
|
|
Name: tz,
|
|
DisplayName: display,
|
|
})
|
|
}
|
|
t.Timezones = options
|
|
t.lastFetched = now
|
|
}
|