gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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 }