I have an optional field on my struct called ExpireTime
. It has a time.Time
type and a json:"expire_time,omitempty"
tag to not send it, when it is empty. This part works perfectly fine.
When I want to use the same field via GRPC, I run into an issue when converting it to the protobuf timestamp format.
type Timestamp struct {
// Represents seconds of UTC time since Unix epoch
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
// 9999-12-31T23:59:59Z inclusive.
Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"`
// Non-negative fractions of a second at nanosecond resolution. Negative
// second values with fractions must still have non-negative nanos values
// that count forward in time. Must be from 0 to 999,999,999
// inclusive.
Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"`
// contains filtered or unexported fields
}
ExpireTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=expire_time,json=expireTime,proto3" json:"expire_time,omitempty"`
The issue is that an empty time.Time{}
object will be converted to a negative seconds
value corresponding to 0001-01-01T00:00:00Z. Having the omitEmpty
flag will not be applied in this case as the value is not zeroed out. What could I do to omit this field, when it is actually empty? Thanks!
CodePudding user response:
Protobuf always includes fields on the wire; there's no (longer) an optional field setting.
Your code will need to use the default value as a signal of non-value.
CodePudding user response:
As you say time.Time{}
converts to 0001-01-01T00:00:00Z
; this is working as intended. Note that you also need to be careful converting in the opposite direction (a zero TimeStamp
will become 1970-01-01T00:00:00Z
).
However generally the Timestamp
will be part of a message, for example:
message MyMessage{
google.protobuf.Timestamp comm_time = 1;
}
Running this through protoc
will result in something like:
type MyMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
CommTime *timestamppb.Timestamp `protobuf:"bytes, 1,opt,name=comm_time,json=commTime,proto3" json:"comm_time,omitempty"`
}
This means you should be able to achieve the result you are looking for with CommTime=nil
; e.g.
sourceTime := time.Time{} // Whatever time you want to encode
var commTime *timestamp.Timestamp
if !sourceTime.IsZero() {
commTime = timestamppb.New(sourceTime)
}
msg := MyMessage{
CommTime: commTime,
}