Closed pequalsnp closed 2 months ago
The disagreement here happens because of a difference of what the zero value of a timestamppb
is, vs the zero value of Golang’s time.Time
value.
Note:
func main() {
var a *timestamppb.Timestamp
var t time.Time
fmt.Println(a.AsTime())
fmt.Println(t)
}
runs and prints:
1970-01-01 00:00:00 +0000 UTC
0001-01-01 00:00:00 +0000 UTC
Note that the zero value of a timestamppb
is the Unix epoch, but the zero value time.Time
is Jan 1st, 1 AD.
Summary: This is intended behavior, even if it is unexpected.
P.S.: Huh, after reading the whole report, you seem to understand all of this already?
This is an unfortunate an edge-case in bridging the Go type system and the protobuf type system and there are no good answers other than being as consistent as possible across the module about how this is handled.
Of note, protoreflect.Message.IsValid says:
// IsValid reports whether the message is valid.
//
// An invalid message is an empty, read-only value.
//
// An invalid message often corresponds to a nil pointer of the concrete
// message type, but the details are implementation dependent.
// Validity is not part of the protobuf data model, and may not
// be preserved in marshaling or other operations.
That is, a nil pointer is semantically treated as an "empty, read-only value".
In the protobuf data model, reading the "seconds" and "nanos" fields of an empty Timestamp
message would report 0, which results in a date of 1970-01-01.
What version of protobuf and what language are you using?
I am using
google.golang.org/protobuf v1.33.0
but the issue is present in the current codeWhat did you do?
If you call
AsTime
on a niltimestamppb.Timestamp
you would expect to get a zero valuetime.Time
back, but what you get is atime.Time
for unix epoch zero, which is not the same thing. See https://go.dev/src/time/time.go?s=8279:8361#L361. Golangtime.Time
zero value is year 1, not 1970.https://github.com/protocolbuffers/protobuf-go/blob/master/types/known/timestamppb/timestamp.pb.go#L199
What did you expect to see?
nil.AsTime().IsZero() == true
What did you see instead?
nil.AsTime().IsZero() == false
That will print
false
Anything else we should know about your project / environment?