github.com/snowflakedb/gosnowflake@v1.9.0/location.go (about) 1 // Copyright (c) 2017-2022 Snowflake Computing Inc. All rights reserved. 2 3 package gosnowflake 4 5 import ( 6 "fmt" 7 "strconv" 8 "sync" 9 "time" 10 ) 11 12 var ( 13 timezones map[int]*time.Location 14 updateTimezoneMutex *sync.Mutex 15 ) 16 17 // Location returns an offset (minutes) based Location object for Snowflake database. 18 func Location(offset int) *time.Location { 19 updateTimezoneMutex.Lock() 20 defer updateTimezoneMutex.Unlock() 21 loc := timezones[offset] 22 if loc != nil { 23 return loc 24 } 25 loc = genTimezone(offset) 26 timezones[offset] = loc 27 return loc 28 } 29 30 // LocationWithOffsetString returns an offset based Location object. The offset string must consist of sHHMI where one sign 31 // character '+'/'-' followed by zero filled hours and minutes. 32 func LocationWithOffsetString(offsets string) (loc *time.Location, err error) { 33 if len(offsets) != 5 { 34 return nil, &SnowflakeError{ 35 Number: ErrInvalidOffsetStr, 36 SQLState: SQLStateInvalidDataTimeFormat, 37 Message: errMsgInvalidOffsetStr, 38 MessageArgs: []interface{}{offsets}, 39 } 40 } 41 if offsets[0] != '-' && offsets[0] != '+' { 42 return nil, &SnowflakeError{ 43 Number: ErrInvalidOffsetStr, 44 SQLState: SQLStateInvalidDataTimeFormat, 45 Message: errMsgInvalidOffsetStr, 46 MessageArgs: []interface{}{offsets}, 47 } 48 } 49 s := 1 50 if offsets[0] == '-' { 51 s = -1 52 } 53 var h, m int64 54 h, err = strconv.ParseInt(offsets[1:3], 10, 64) 55 if err != nil { 56 return 57 } 58 m, err = strconv.ParseInt(offsets[3:], 10, 64) 59 if err != nil { 60 return 61 } 62 offset := s * (int(h)*60 + int(m)) 63 loc = Location(offset) 64 return 65 } 66 67 func genTimezone(offset int) *time.Location { 68 var offsetSign string 69 var toffset int 70 if offset < 0 { 71 offsetSign = "-" 72 toffset = -offset 73 } else { 74 offsetSign = "+" 75 toffset = offset 76 } 77 logger.Debugf("offset: %v", offset) 78 return time.FixedZone( 79 fmt.Sprintf("%v%02d%02d", 80 offsetSign, toffset/60, toffset%60), int(offset)*60) 81 } 82 83 func init() { 84 updateTimezoneMutex = &sync.Mutex{} 85 timezones = make(map[int]*time.Location, 48) 86 // pre-generate all common timezones 87 for i := -720; i <= 720; i += 30 { 88 logger.Debugf("offset: %v", i) 89 timezones[i] = genTimezone(i) 90 } 91 } 92 93 // retrieve current location based on connection 94 func getCurrentLocation(params map[string]*string) *time.Location { 95 loc := time.Now().Location() 96 var err error 97 paramsMutex.Lock() 98 if tz, ok := params["timezone"]; ok && tz != nil { 99 loc, err = time.LoadLocation(*tz) 100 if err != nil { 101 loc = time.Now().Location() 102 } 103 } 104 paramsMutex.Unlock() 105 return loc 106 }