Selaa lähdekoodia

Merge pull request #441 from mondough/fixtimemarshaling

Fix timestamp type marshaling
Chris Bannister 10 vuotta sitten
vanhempi
commit
2d025059ea
3 muutettua tiedostoa jossa 71 lisäystä ja 1 poistoa
  1. 1 0
      AUTHORS
  2. 4 1
      marshal.go
  3. 66 0
      marshal_test.go

+ 1 - 0
AUTHORS

@@ -49,3 +49,4 @@ Zach Badgett <zach.badgett@gmail.com>
 Maciek Sakrejda <maciek@heroku.com>
 Jeff Mitchell <jeffrey.mitchell@gmail.com>
 Baptiste Fontaine <b@ptistefontaine.fr>
+Matt Heath <matt@mattheath.com>

+ 4 - 1
marshal.go

@@ -802,7 +802,10 @@ func marshalTimestamp(info TypeInfo, value interface{}) ([]byte, error) {
 	case int64:
 		return encBigInt(v), nil
 	case time.Time:
-		x := v.UnixNano() / int64(1000000)
+		if v.IsZero() {
+			return []byte{}, nil
+		}
+		x := int64(v.UTC().Unix()*1e3) + int64(v.UTC().Nanosecond()/1e6)
 		return encBigInt(x), nil
 	}
 	rv := reflect.ValueOf(value)

+ 66 - 0
marshal_test.go

@@ -794,3 +794,69 @@ func TestMarshalPointer(t *testing.T) {
 		t.Errorf("Pointer marshaling failed. Expected %+v, got %+v", []byte{42}, data)
 	}
 }
+
+func TestMarshalTimestamp(t *testing.T) {
+	var marshalTimestampTests = []struct {
+		Info  TypeInfo
+		Data  []byte
+		Value interface{}
+	}{
+		{
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\x00\x00\x01\x40\x77\x16\xe1\xb8"),
+			time.Date(2013, time.August, 13, 9, 52, 3, 0, time.UTC),
+		},
+		{
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\x00\x00\x01\x40\x77\x16\xe1\xb8"),
+			int64(1376387523000),
+		},
+		{
+			// 9223372036854 is the maximum time representable in ms since the epoch
+			// with int64 if using UnixNano to convert
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\x00\x00\x08\x63\x7b\xd0\x5a\xf6"),
+			time.Date(2262, time.April, 11, 23, 47, 16, 854775807, time.UTC),
+		},
+		{
+			// One nanosecond after causes overflow when using UnixNano
+			// Instead it should resolve to the same time in ms
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\x00\x00\x08\x63\x7b\xd0\x5a\xf6"),
+			time.Date(2262, time.April, 11, 23, 47, 16, 854775808, time.UTC),
+		},
+		{
+			// -9223372036855 is the minimum time representable in ms since the epoch
+			// with int64 if using UnixNano to convert
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\xff\xff\xf7\x9c\x84\x2f\xa5\x09"),
+			time.Date(1677, time.September, 21, 00, 12, 43, 145224192, time.UTC),
+		},
+		{
+			// One nanosecond earlier causes overflow when using UnixNano
+			// it should resolve to the same time in ms
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte("\xff\xff\xf7\x9c\x84\x2f\xa5\x09"),
+			time.Date(1677, time.September, 21, 00, 12, 43, 145224191, time.UTC),
+		},
+		{
+			// Store the zero time as a blank slice
+			NativeType{proto: 2, typ: TypeTimestamp},
+			[]byte{},
+			time.Time{},
+		},
+	}
+
+	for i, test := range marshalTimestampTests {
+		t.Log(i, test)
+		data, err := Marshal(test.Info, test.Value)
+		if err != nil {
+			t.Errorf("marshalTest[%d]: %v", i, err)
+			continue
+		}
+		if !bytes.Equal(data, test.Data) {
+			t.Errorf("marshalTest[%d]: expected %x (%v), got %x (%v) for time %s", i,
+				test.Data, decBigInt(test.Data), data, decBigInt(data), test.Value)
+		}
+	}
+}