bug fix:修复可能的panic状态;增加更多功能
This commit is contained in:
@@ -0,0 +1,359 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user