forked from goccy/go-zetasqlite
/
util.go
84 lines (76 loc) · 2.24 KB
/
util.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
package internal
import (
"fmt"
"regexp"
"strconv"
"sync"
"time"
)
var (
timeZoneOffsetPartialPattern = regexp.MustCompile(`([-+][0-9]{2})`)
timeZoneOffsetPattern = regexp.MustCompile(`([-+][0-9]{2}):([0-9]{2})`)
locationCacheMap = map[string]*time.Location{}
locationCacheMu sync.RWMutex
)
func getCachedLocation(timeZone string) *time.Location {
locationCacheMu.RLock()
defer locationCacheMu.RUnlock()
if loc, exists := locationCacheMap[timeZone]; exists {
return loc
}
if loc, exists := locationCacheMap[fmt.Sprintf("UTC%s", timeZone)]; exists {
return loc
}
return nil
}
func setLocationCache(key string, loc *time.Location) {
locationCacheMu.Lock()
locationCacheMap[key] = loc
locationCacheMu.Unlock()
}
func toLocation(timeZone string) (*time.Location, error) {
if loc := getCachedLocation(timeZone); loc != nil {
return loc, nil
}
if matched := timeZoneOffsetPattern.FindAllStringSubmatch(timeZone, -1); len(matched) != 0 && len(matched[0]) == 3 {
offsetHour := matched[0][1]
offsetMin := matched[0][2]
hour, err := strconv.ParseInt(offsetHour, 10, 64)
if err != nil {
return nil, err
}
min, err := strconv.ParseInt(offsetMin, 10, 64)
if err != nil {
return nil, err
}
locName := fmt.Sprintf("UTC%s", timeZone)
loc := time.FixedZone(locName, int(hour)*60*60+int(min)*60)
setLocationCache(locName, loc)
return loc, nil
}
if matched := timeZoneOffsetPartialPattern.FindAllStringSubmatch(timeZone, -1); len(matched) != 0 && len(matched[0]) == 2 {
offset := matched[0][1]
hour, err := strconv.ParseInt(offset, 10, 64)
if err != nil {
return nil, err
}
locName := fmt.Sprintf("UTC%s", timeZone)
loc := time.FixedZone(locName, int(hour)*60*60)
setLocationCache(locName, loc)
return loc, nil
}
loc, err := time.LoadLocation(timeZone)
if err != nil {
return nil, fmt.Errorf("failed to load location from %s: %w", timeZone, err)
}
setLocationCache(timeZone, loc)
return loc, nil
}
func modifyTimeZone(t time.Time, loc *time.Location) (time.Time, error) {
// remove timezone parameter from time
format := t.Format("2006-01-02T15:04:05.999999999")
return parseTimestamp(format, loc)
}
func timeFromUnixNano(unixNano int64) time.Time {
return time.Unix(0, unixNano)
}