360 lines
7.1 KiB
Go
360 lines
7.1 KiB
Go
|
|
package convert
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
var defaultNullTimeLayouts = []string{
|
||
|
|
time.RFC3339Nano,
|
||
|
|
time.RFC3339,
|
||
|
|
"2006-01-02 15:04:05",
|
||
|
|
"2006-01-02",
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToInt64 converts any value to int64.
|
||
|
|
func ToInt64(val interface{}) int64 {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return 0
|
||
|
|
case int:
|
||
|
|
return int64(v)
|
||
|
|
case int32:
|
||
|
|
return int64(v)
|
||
|
|
case int64:
|
||
|
|
return v
|
||
|
|
case uint64:
|
||
|
|
return int64(v)
|
||
|
|
case float32:
|
||
|
|
return int64(v)
|
||
|
|
case float64:
|
||
|
|
return int64(v)
|
||
|
|
case string:
|
||
|
|
result, _ := strconv.ParseInt(v, 10, 64)
|
||
|
|
return result
|
||
|
|
case bool:
|
||
|
|
if v {
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
case time.Time:
|
||
|
|
return v.Unix()
|
||
|
|
case []byte:
|
||
|
|
result, _ := strconv.ParseInt(string(v), 10, 64)
|
||
|
|
return result
|
||
|
|
default:
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToUint64 converts any value to uint64.
|
||
|
|
func ToUint64(val interface{}) uint64 {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return 0
|
||
|
|
case int:
|
||
|
|
return uint64(v)
|
||
|
|
case int32:
|
||
|
|
return uint64(v)
|
||
|
|
case int64:
|
||
|
|
return uint64(v)
|
||
|
|
case uint64:
|
||
|
|
return v
|
||
|
|
case float32:
|
||
|
|
return uint64(v)
|
||
|
|
case float64:
|
||
|
|
return uint64(v)
|
||
|
|
case string:
|
||
|
|
result, _ := strconv.ParseUint(v, 10, 64)
|
||
|
|
return result
|
||
|
|
case bool:
|
||
|
|
if v {
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
case time.Time:
|
||
|
|
return uint64(v.Unix())
|
||
|
|
case []byte:
|
||
|
|
result, _ := strconv.ParseUint(string(v), 10, 64)
|
||
|
|
return result
|
||
|
|
default:
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToFloat64 converts any value to float64.
|
||
|
|
func ToFloat64(val interface{}) float64 {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return 0
|
||
|
|
case int:
|
||
|
|
return float64(v)
|
||
|
|
case int32:
|
||
|
|
return float64(v)
|
||
|
|
case int64:
|
||
|
|
return float64(v)
|
||
|
|
case uint64:
|
||
|
|
return float64(v)
|
||
|
|
case float32:
|
||
|
|
return float64(v)
|
||
|
|
case float64:
|
||
|
|
return v
|
||
|
|
case string:
|
||
|
|
result, _ := strconv.ParseFloat(v, 64)
|
||
|
|
return result
|
||
|
|
case bool:
|
||
|
|
if v {
|
||
|
|
return 1
|
||
|
|
}
|
||
|
|
return 0
|
||
|
|
case time.Time:
|
||
|
|
return float64(v.Unix())
|
||
|
|
case []byte:
|
||
|
|
result, _ := strconv.ParseFloat(string(v), 64)
|
||
|
|
return result
|
||
|
|
default:
|
||
|
|
return 0
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToBool converts any value to bool.
|
||
|
|
func ToBool(val interface{}) bool {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return false
|
||
|
|
case bool:
|
||
|
|
return v
|
||
|
|
case int:
|
||
|
|
return v != 0
|
||
|
|
case int32:
|
||
|
|
return v != 0
|
||
|
|
case int64:
|
||
|
|
return v != 0
|
||
|
|
case uint64:
|
||
|
|
return v != 0
|
||
|
|
case float32:
|
||
|
|
return v != 0
|
||
|
|
case float64:
|
||
|
|
return v != 0
|
||
|
|
case string:
|
||
|
|
result, _ := strconv.ParseBool(v)
|
||
|
|
return result
|
||
|
|
case []byte:
|
||
|
|
result, _ := strconv.ParseBool(string(v))
|
||
|
|
return result
|
||
|
|
default:
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToTime converts any value to time.Time.
|
||
|
|
func ToTime(val interface{}, layout string) time.Time {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return time.Time{}
|
||
|
|
case time.Time:
|
||
|
|
return v
|
||
|
|
case int:
|
||
|
|
return time.Unix(int64(v), 0)
|
||
|
|
case int32:
|
||
|
|
return time.Unix(int64(v), 0)
|
||
|
|
case int64:
|
||
|
|
return time.Unix(v, 0)
|
||
|
|
case uint64:
|
||
|
|
return time.Unix(int64(v), 0)
|
||
|
|
case float32:
|
||
|
|
sec := int64(v)
|
||
|
|
nsec := int64((v - float32(sec)) * 1e9)
|
||
|
|
return time.Unix(sec, nsec)
|
||
|
|
case float64:
|
||
|
|
sec := int64(v)
|
||
|
|
nsec := int64((v - float64(sec)) * 1e9)
|
||
|
|
return time.Unix(sec, nsec)
|
||
|
|
case string:
|
||
|
|
result, _ := time.Parse(layout, v)
|
||
|
|
return result
|
||
|
|
case []byte:
|
||
|
|
result, _ := time.Parse(layout, string(v))
|
||
|
|
return result
|
||
|
|
default:
|
||
|
|
return time.Time{}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToInt64Safe converts any value to int64 with error handling.
|
||
|
|
func ToInt64Safe(val interface{}) (int64, error) {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return 0, nil
|
||
|
|
case int:
|
||
|
|
return int64(v), nil
|
||
|
|
case int32:
|
||
|
|
return int64(v), nil
|
||
|
|
case int64:
|
||
|
|
return v, nil
|
||
|
|
case uint64:
|
||
|
|
return int64(v), nil
|
||
|
|
case float32:
|
||
|
|
return int64(v), nil
|
||
|
|
case float64:
|
||
|
|
return int64(v), nil
|
||
|
|
case string:
|
||
|
|
return strconv.ParseInt(v, 10, 64)
|
||
|
|
case bool:
|
||
|
|
if v {
|
||
|
|
return 1, nil
|
||
|
|
}
|
||
|
|
return 0, nil
|
||
|
|
case time.Time:
|
||
|
|
return v.Unix(), nil
|
||
|
|
case []byte:
|
||
|
|
return strconv.ParseInt(string(v), 10, 64)
|
||
|
|
default:
|
||
|
|
return 0, fmt.Errorf("cannot convert %T to int64", val)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToStringSafe converts any value to string with error handling.
|
||
|
|
func ToStringSafe(val interface{}) (string, error) {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return "", nil
|
||
|
|
case string:
|
||
|
|
return v, nil
|
||
|
|
case int:
|
||
|
|
return strconv.Itoa(v), nil
|
||
|
|
case int32:
|
||
|
|
return strconv.FormatInt(int64(v), 10), nil
|
||
|
|
case int64:
|
||
|
|
return strconv.FormatInt(v, 10), nil
|
||
|
|
case float32:
|
||
|
|
return strconv.FormatFloat(float64(v), 'f', -1, 32), nil
|
||
|
|
case float64:
|
||
|
|
return strconv.FormatFloat(v, 'f', -1, 64), nil
|
||
|
|
case bool:
|
||
|
|
return strconv.FormatBool(v), nil
|
||
|
|
case time.Time:
|
||
|
|
return v.String(), nil
|
||
|
|
case []byte:
|
||
|
|
return string(v), nil
|
||
|
|
default:
|
||
|
|
return "", fmt.Errorf("cannot convert %T to string", val)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToFloat64Safe converts any value to float64 with error handling.
|
||
|
|
func ToFloat64Safe(val interface{}) (float64, error) {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return 0, nil
|
||
|
|
case float64:
|
||
|
|
return v, nil
|
||
|
|
case float32:
|
||
|
|
return float64(v), nil
|
||
|
|
case int, int32, int64, uint64:
|
||
|
|
intVal, err := ToInt64Safe(v)
|
||
|
|
return float64(intVal), err
|
||
|
|
case string:
|
||
|
|
return strconv.ParseFloat(v, 64)
|
||
|
|
case []byte:
|
||
|
|
return strconv.ParseFloat(string(v), 64)
|
||
|
|
default:
|
||
|
|
return 0, fmt.Errorf("cannot convert %T to float64", val)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToBoolSafe converts any value to bool with error handling.
|
||
|
|
func ToBoolSafe(val interface{}) (bool, error) {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return false, nil
|
||
|
|
case bool:
|
||
|
|
return v, nil
|
||
|
|
case int:
|
||
|
|
return v != 0, nil
|
||
|
|
case int8:
|
||
|
|
return v != 0, nil
|
||
|
|
case int16:
|
||
|
|
return v != 0, nil
|
||
|
|
case int32:
|
||
|
|
return v != 0, nil
|
||
|
|
case int64:
|
||
|
|
return v != 0, nil
|
||
|
|
case uint:
|
||
|
|
return v != 0, nil
|
||
|
|
case uint8:
|
||
|
|
return v != 0, nil
|
||
|
|
case uint16:
|
||
|
|
return v != 0, nil
|
||
|
|
case uint32:
|
||
|
|
return v != 0, nil
|
||
|
|
case uint64:
|
||
|
|
return v != 0, nil
|
||
|
|
case float32:
|
||
|
|
return v != 0, nil
|
||
|
|
case float64:
|
||
|
|
return v != 0, nil
|
||
|
|
case string:
|
||
|
|
return ParseBoolString(v)
|
||
|
|
case []byte:
|
||
|
|
return ParseBoolString(string(v))
|
||
|
|
default:
|
||
|
|
return false, fmt.Errorf("cannot convert %T to bool", val)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ParseBoolString parses string-like bool values.
|
||
|
|
func ParseBoolString(raw string) (bool, error) {
|
||
|
|
normalized := strings.TrimSpace(strings.ToLower(raw))
|
||
|
|
switch normalized {
|
||
|
|
case "", "0", "false", "f", "off", "no", "n":
|
||
|
|
return false, nil
|
||
|
|
case "1", "true", "t", "on", "yes", "y":
|
||
|
|
return true, nil
|
||
|
|
default:
|
||
|
|
return false, fmt.Errorf("cannot parse bool value: %q", raw)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ToTimeSafe converts any value to time.Time with error handling.
|
||
|
|
func ToTimeSafe(val interface{}) (time.Time, error) {
|
||
|
|
switch v := val.(type) {
|
||
|
|
case nil:
|
||
|
|
return time.Time{}, nil
|
||
|
|
case time.Time:
|
||
|
|
return v, nil
|
||
|
|
case int:
|
||
|
|
return time.Unix(int64(v), 0), nil
|
||
|
|
case int64:
|
||
|
|
return time.Unix(v, 0), nil
|
||
|
|
case string:
|
||
|
|
return ParseTimeValue(v)
|
||
|
|
case []byte:
|
||
|
|
return ParseTimeValue(string(v))
|
||
|
|
default:
|
||
|
|
return time.Time{}, fmt.Errorf("cannot convert %T to time.Time", val)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ParseTimeValue parses common SQL date-time formats and unix timestamp.
|
||
|
|
func ParseTimeValue(raw string) (time.Time, error) {
|
||
|
|
trimmed := strings.TrimSpace(raw)
|
||
|
|
if trimmed == "" {
|
||
|
|
return time.Time{}, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, layout := range defaultNullTimeLayouts {
|
||
|
|
if t, err := time.Parse(layout, trimmed); err == nil {
|
||
|
|
return t, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if ts, err := strconv.ParseInt(trimmed, 10, 64); err == nil {
|
||
|
|
return time.Unix(ts, 0), nil
|
||
|
|
}
|
||
|
|
|
||
|
|
return time.Time{}, fmt.Errorf("cannot parse time value: %q", raw)
|
||
|
|
}
|