You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

135 lines
2.7 KiB

  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. secs := uint64(tm.Unix())
  26. if secs>>34 == 0 {
  27. data := uint64(tm.Nanosecond())<<34 | secs
  28. if data&0xffffffff00000000 == 0 {
  29. b := make([]byte, 4)
  30. binary.BigEndian.PutUint32(b, uint32(data))
  31. return b
  32. } else {
  33. b := make([]byte, 8)
  34. binary.BigEndian.PutUint64(b, data)
  35. return b
  36. }
  37. }
  38. b := make([]byte, 12)
  39. binary.BigEndian.PutUint32(b, uint32(tm.Nanosecond()))
  40. binary.BigEndian.PutUint64(b[4:], uint64(secs))
  41. return b
  42. }
  43. func (d *Decoder) DecodeTime() (time.Time, error) {
  44. tm, err := d.decodeTime()
  45. if err != nil {
  46. return tm, err
  47. }
  48. if tm.IsZero() {
  49. // Assume that zero time does not have timezone information.
  50. return tm.UTC(), nil
  51. }
  52. return tm, nil
  53. }
  54. func (d *Decoder) decodeTime() (time.Time, error) {
  55. extLen := d.extLen
  56. d.extLen = 0
  57. if extLen == 0 {
  58. c, err := d.readCode()
  59. if err != nil {
  60. return time.Time{}, err
  61. }
  62. // Legacy format.
  63. if c == codes.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. extLen, err = d.parseExtLen(c)
  75. if err != nil {
  76. return time.Time{}, err
  77. }
  78. // Skip ext id.
  79. _, err = d.s.ReadByte()
  80. if err != nil {
  81. return time.Time{}, nil
  82. }
  83. }
  84. b, err := d.readN(extLen)
  85. if err != nil {
  86. return time.Time{}, err
  87. }
  88. switch len(b) {
  89. case 4:
  90. sec := binary.BigEndian.Uint32(b)
  91. return time.Unix(int64(sec), 0), nil
  92. case 8:
  93. sec := binary.BigEndian.Uint64(b)
  94. nsec := int64(sec >> 34)
  95. sec &= 0x00000003ffffffff
  96. return time.Unix(int64(sec), nsec), nil
  97. case 12:
  98. nsec := binary.BigEndian.Uint32(b)
  99. sec := binary.BigEndian.Uint64(b[4:])
  100. return time.Unix(int64(sec), int64(nsec)), nil
  101. default:
  102. err = fmt.Errorf("msgpack: invalid ext len=%d decoding time", extLen)
  103. return time.Time{}, err
  104. }
  105. }
  106. func encodeTimeValue(e *Encoder, v reflect.Value) error {
  107. tm := v.Interface().(time.Time)
  108. b := e.encodeTime(tm)
  109. return e.write(b)
  110. }
  111. func decodeTimeValue(d *Decoder, v reflect.Value) error {
  112. tm, err := d.DecodeTime()
  113. if err != nil {
  114. return err
  115. }
  116. v.Set(reflect.ValueOf(tm))
  117. return nil
  118. }