time.go (2886B)
1 package msgpack 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "reflect" 7 "time" 8 9 "github.com/vmihailenco/msgpack/v5/msgpcode" 10 ) 11 12 var timeExtID int8 = -1 13 14 func init() { 15 RegisterExtEncoder(timeExtID, time.Time{}, timeEncoder) 16 RegisterExtDecoder(timeExtID, time.Time{}, timeDecoder) 17 } 18 19 func timeEncoder(e *Encoder, v reflect.Value) ([]byte, error) { 20 return e.encodeTime(v.Interface().(time.Time)), nil 21 } 22 23 func timeDecoder(d *Decoder, v reflect.Value, extLen int) error { 24 tm, err := d.decodeTime(extLen) 25 if err != nil { 26 return err 27 } 28 29 ptr := v.Addr().Interface().(*time.Time) 30 *ptr = tm 31 32 return nil 33 } 34 35 func (e *Encoder) EncodeTime(tm time.Time) error { 36 b := e.encodeTime(tm) 37 if err := e.encodeExtLen(len(b)); err != nil { 38 return err 39 } 40 if err := e.w.WriteByte(byte(timeExtID)); err != nil { 41 return err 42 } 43 return e.write(b) 44 } 45 46 func (e *Encoder) encodeTime(tm time.Time) []byte { 47 if e.timeBuf == nil { 48 e.timeBuf = make([]byte, 12) 49 } 50 51 secs := uint64(tm.Unix()) 52 if secs>>34 == 0 { 53 data := uint64(tm.Nanosecond())<<34 | secs 54 55 if data&0xffffffff00000000 == 0 { 56 b := e.timeBuf[:4] 57 binary.BigEndian.PutUint32(b, uint32(data)) 58 return b 59 } 60 61 b := e.timeBuf[:8] 62 binary.BigEndian.PutUint64(b, data) 63 return b 64 } 65 66 b := e.timeBuf[:12] 67 binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond())) 68 binary.BigEndian.PutUint64(b[4:], secs) 69 return b 70 } 71 72 func (d *Decoder) DecodeTime() (time.Time, error) { 73 c, err := d.readCode() 74 if err != nil { 75 return time.Time{}, err 76 } 77 78 // Legacy format. 79 if c == msgpcode.FixedArrayLow|2 { 80 sec, err := d.DecodeInt64() 81 if err != nil { 82 return time.Time{}, err 83 } 84 85 nsec, err := d.DecodeInt64() 86 if err != nil { 87 return time.Time{}, err 88 } 89 90 return time.Unix(sec, nsec), nil 91 } 92 93 if msgpcode.IsString(c) { 94 s, err := d.string(c) 95 if err != nil { 96 return time.Time{}, err 97 } 98 return time.Parse(time.RFC3339Nano, s) 99 } 100 101 extID, extLen, err := d.extHeader(c) 102 if err != nil { 103 return time.Time{}, err 104 } 105 106 if extID != timeExtID { 107 return time.Time{}, fmt.Errorf("msgpack: invalid time ext id=%d", extID) 108 } 109 110 tm, err := d.decodeTime(extLen) 111 if err != nil { 112 return tm, err 113 } 114 115 if tm.IsZero() { 116 // Zero time does not have timezone information. 117 return tm.UTC(), nil 118 } 119 return tm, nil 120 } 121 122 func (d *Decoder) decodeTime(extLen int) (time.Time, error) { 123 b, err := d.readN(extLen) 124 if err != nil { 125 return time.Time{}, err 126 } 127 128 switch len(b) { 129 case 4: 130 sec := binary.BigEndian.Uint32(b) 131 return time.Unix(int64(sec), 0), nil 132 case 8: 133 sec := binary.BigEndian.Uint64(b) 134 nsec := int64(sec >> 34) 135 sec &= 0x00000003ffffffff 136 return time.Unix(int64(sec), nsec), nil 137 case 12: 138 nsec := binary.BigEndian.Uint32(b) 139 sec := binary.BigEndian.Uint64(b[4:]) 140 return time.Unix(int64(sec), int64(nsec)), nil 141 default: 142 err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen) 143 return time.Time{}, err 144 } 145 }