time.go 2.9 KB

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