github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/timex/jsontime.go (about)

     1  package timex
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"strings"
     7  	"time"
     8  
     9  	perrors "github.com/pkg/errors"
    10  )
    11  
    12  // ErrUnknownTimeFormat defines the error type for unknown time format.
    13  var ErrUnknownTimeFormat = errors.New("unknown errors time format")
    14  
    15  // JSONTime defines a time.Time that can be used in struct tag for JSON unmarshalling.
    16  type JSONTime time.Time
    17  
    18  // UnmarshalJSON unmarshals bytes to JSONTime.
    19  func (t *JSONTime) UnmarshalJSON(b []byte) error {
    20  	v, _ := TryUnQuoted(string(b))
    21  	if v == "" {
    22  		return nil
    23  	}
    24  
    25  	// 首先看是否是数字,表示毫秒数或者纳秒数
    26  	if p, err := strconv.ParseInt(v, 10, 64); err == nil {
    27  		*t = JSONTime(time.Unix(0, p*1000000)) // milliseconds range, 1 millis = 1000,000 nanos)
    28  		return nil
    29  	}
    30  
    31  	v = strings.ReplaceAll(v, "/", "-")
    32  	v = strings.ReplaceAll(v, ",", ".")
    33  	v = strings.ReplaceAll(v, "T", " ")
    34  
    35  	parser := func(layout, value string) (time.Time, error) {
    36  		return time.ParseInLocation(layout, value, time.Local)
    37  	}
    38  
    39  	if strings.Contains(v, "Z") {
    40  		if strings.HasSuffix(v, "Z") {
    41  			v = strings.TrimSuffix(v, "Z")
    42  		}
    43  		parser = func(layout, value string) (time.Time, error) {
    44  			return time.Parse(layout, value)
    45  		}
    46  	}
    47  
    48  	for _, f := range []string{
    49  		"2006-01-02 15:04:05.999999999Z07:00", // time.RFC3339Nano,
    50  		"2006-01-02 15:04:05Z07:00",           // time.RFC3339,
    51  		"2006-01-02 15:04:05.000000",
    52  		"2006-01-02 15:04:05.000",
    53  	} {
    54  		if tt, err := parser(f, v); err == nil {
    55  			*t = JSONTime(tt)
    56  			return nil
    57  		}
    58  	}
    59  
    60  	return perrors.Wrapf(ErrUnknownTimeFormat, "value %s has unknown time format"+v)
    61  }
    62  
    63  // TryUnQuoted tries to unquote string.
    64  func TryUnQuoted(v string) (string, bool) {
    65  	vlen := len(v)
    66  	yes := vlen >= 2 && v[0] == '"' && v[vlen-1] == '"'
    67  	if !yes {
    68  		return v, false
    69  	}
    70  
    71  	return v[1 : vlen-1], true
    72  }