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  }