2
votes

I am creating a Go application which will use GRPC and protobuf. My RPC service shall take a message containing the type google.protobuf.Timestamp, parse it and eventually save it in a database or perform some more operations on it.

I am confused as to what is considered valid input for the type google.protobuf.Timestamp. I wish to use the following format for the datetimestamp with the timezone offset.

2019-02-15T13:00:00+01:00

Here is the proto file I am using.

syntax = "proto3"
package example;
import "google/protobuf/timestamp.proto"

service Tester {
 rpc ParseDateTimeStamp(TSRequest) returns (TSReply) {}
}

message TSRequest {
  google.protobuf.Timestamp dts = 1;
}

message TSReply {
 string message = 1;
}

The issue is that when I send a message to the GRPC server containing the datetimestamp. I would expect that the type *tsbp.Timestamp for the 2019-02-15T13:00:00+01:00 datetimestamp given to be valid and give me the appropriate seconds from epoch. (After invoking GetSeconds() from the timestamp.go)

Invoking ptypes.TimestampString(ts *tspb.Timestamp) returns 1970-01-01T00:00:00Z for the example input above.

Does the google.protobuf.Timestamp accept datetimestamps with the +- offset?

Or do I have to have the input in a String type and then parse to time.Time with time.Format instead of using the timestamp variable type in protobuf? If so could you provide an example of this?

1
when returning the TSReply message - do you want it to include the original timezone offset? If so, your input value of ptype.Timestamp does not have the storage of a TZ value, so any offset would need to be included in an extra field.colm.anseo

1 Answers

4
votes

A gRPC message type of google.protobuf.Timestamp, internally, is just two int64's

message Timestamp {
  // 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.
  int64 seconds = 1;

  // 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.
  int32 nanos = 2;
}

So when in this format-type, there is nothing to parse.

One typically takes:

  • a string format like your 2019-02-15T13:00:00+01:00 and converts to a time.Time using time.Parse
  • then convert the time.Time to a *tspb.Timestamp using ptypes.TimestampProto()

FYI in your cited output, you are seeing a zero timestamp (i.e. both seconds and nanos are zero) - hence the "1970-01-01T00:00:00Z" output.


Implementing the flow above:

ts, err := time.Parse(time.RFC3339, "2019-02-15T13:00:00+01:00")

pbts, err := ptypes.TimestampProto(ts) // ptypes.Timestamp:"seconds:1550232000 "

fmt.Println(ptypes.TimestampString(pbts)) // "2019-02-15T12:00:00Z"

Playground

Note: the ptype.Timestamp is stripped of any timezone - Z so UTC time. So if you need to preserve timezone of a time.Time, the offset would need to be sent in your gRPC message in addition to your google.protobuf.Timestamp message.