Marshal MicroTime to json and proto at the same precision

This commit is contained in:
Hao Ruan 2022-08-19 18:30:53 +08:00
parent 132f29769d
commit 7aa80add91
2 changed files with 74 additions and 3 deletions

View File

@ -27,9 +27,12 @@ func (m *MicroTime) ProtoMicroTime() *Timestamp {
if m == nil {
return &Timestamp{}
}
// truncate precision to microseconds to match JSON marshaling/unmarshaling
truncatedNanoseconds := time.Duration(m.Time.Nanosecond()).Truncate(time.Microsecond)
return &Timestamp{
Seconds: m.Time.Unix(),
Nanos: int32(m.Time.Nanosecond()),
Nanos: int32(truncatedNanoseconds),
}
}
@ -51,7 +54,10 @@ func (m *MicroTime) Unmarshal(data []byte) error {
if err := p.Unmarshal(data); err != nil {
return err
}
m.Time = time.Unix(p.Seconds, int64(p.Nanos)).Local()
// truncate precision to microseconds to match JSON marshaling/unmarshaling
truncatedNanoseconds := time.Duration(p.Nanos).Truncate(time.Microsecond)
m.Time = time.Unix(p.Seconds, int64(truncatedNanoseconds)).Local()
return nil
}

View File

@ -118,7 +118,7 @@ func TestMicroTimeProto(t *testing.T) {
input MicroTime
}{
{MicroTime{}},
{DateMicro(1998, time.May, 5, 1, 5, 5, 50, time.Local)},
{DateMicro(1998, time.May, 5, 1, 5, 5, 1000, time.Local)},
{DateMicro(1998, time.May, 5, 5, 5, 5, 0, time.Local)},
}
@ -253,3 +253,68 @@ func TestMicroTimeIsZero(t *testing.T) {
})
}
}
func TestMicroTimeUnmarshalJSONAndProtoEqual(t *testing.T) {
cases := []struct {
name string
input MicroTime
result bool
}{
{"nanosecond level precision", UnixMicro(123, 123123123), true},
{"microsecond level precision", UnixMicro(123, 123123000), true},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
jsonData, err := c.input.MarshalJSON()
if err != nil {
t.Fatalf("Failed to marshal input to JSON: '%v': %v", c.input, err)
}
protoData, err := c.input.Marshal()
if err != nil {
t.Fatalf("Failed to marshal input to proto: '%v': %v", c.input, err)
}
var tJSON, tProto MicroTime
if err = tJSON.UnmarshalJSON(jsonData); err != nil {
t.Fatalf("Failed to unmarshal JSON: '%v': %v", jsonData, err)
}
if err = tProto.Unmarshal(protoData); err != nil {
t.Fatalf("Failed to unmarshal proto: '%v': %v", protoData, err)
}
result := tJSON.Equal(&tProto)
if result != c.result {
t.Errorf("Failed equality test for '%v': expected %+v, got %+v", c.input, c.result, result)
}
})
}
}
func TestMicroTimeProtoUnmarshalRaw(t *testing.T) {
cases := []struct {
name string
input []byte
expected MicroTime
}{
// input is generated by Timestamp{123, 123123123}.Marshal()
{"nanosecond level precision", []byte{8, 123, 16, 179, 235, 218, 58}, UnixMicro(123, 123123000)},
// input is generated by Timestamp{123, 123123000}.Marshal()
{"microsecond level precision", []byte{8, 123, 16, 184, 234, 218, 58}, UnixMicro(123, 123123000)},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var actual MicroTime
if err := actual.Unmarshal(c.input); err != nil {
t.Fatalf("Failed to unmarshal proto: '%v': %v", c.input, err)
}
if !actual.Equal(&c.expected) {
t.Errorf("Failed unmarshal from nanosecond-precise raw for '%v': expected %+v, got %+v", c.input, c.expected, actual)
}
})
}
}