go/datetime.go (55 lines of code) (raw):

// Copyright (c) 2022 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. package athenadriver import ( "fmt" "strings" "time" "unicode" ) // AthenaTime represents a time.Time value that can be null. // The AthenaTime supports Athena's Date, Time and Timestamp data types, // with or without time zone. type AthenaTime struct { Time time.Time Valid bool } var timeLayouts = []string{ "2006-01-02", "15:04:05.000", "2006-01-02 15:04:05.000000000", "2006-01-02 15:04:05.000000", "2006-01-02 15:04:05.000", } func scanTime(vv string) (AthenaTime, error) { parts := strings.Split(vv, " ") if len(parts) > 1 && !unicode.IsDigit(rune(parts[len(parts)-1][0])) { return parseAthenaTimeWithLocation(vv) } return parseAthenaTime(vv) } func parseAthenaTime(v string) (AthenaTime, error) { var t time.Time var err error for _, layout := range timeLayouts { t, err = time.ParseInLocation(layout, v, time.Local) if err == nil { return AthenaTime{Valid: true, Time: t}, nil } } return AthenaTime{}, err } func parseAthenaTimeWithLocation(v string) (AthenaTime, error) { idx := strings.LastIndex(v, " ") if idx == -1 { return AthenaTime{}, fmt.Errorf("cannot convert %v (%T) to time+zone", v, v) } stamp, location := v[:idx], v[idx+1:] loc, err := time.LoadLocation(location) if err != nil { return AthenaTime{}, fmt.Errorf("cannot load timezone %q: %v", location, err) } var t time.Time for _, layout := range timeLayouts { t, err = time.ParseInLocation(layout, stamp, loc) if err == nil { return AthenaTime{Valid: true, Time: t}, nil } } return AthenaTime{}, err }