time.go 3.0 KB

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