time.go 2.8 KB

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