理系学生日記

おまえはいつまで学生気分なのか

Protocol Buffer で時刻(タイムスタンプ)を扱いたい

API でのリクエスト、レスポンスのフィールドとして、タイムスタンプを定義したいときがあります。 しかし、Protocol Buffer の言語仕様上、Scalar として日付、時刻関連の型は定義されていません。このようなとき、どのように対処すれば良いでしょうか。

日付 + 時刻については google.protobuf.Timestamp を使う

以下のように書けば良いです。

import "google/protobuf/timestamp.proto";

// The response message containing the greetings
message HelloReply {
  google.protobuf.Timestamp timestamp = 1;
  string message = 2;
}

ちょっと解説しておくと、時刻情報は確かに Protocol Buffer の Scalar 型としては定義されていません。しかし、それは必ずしも時刻を Protocol Buffer で扱えないことを意味しません。

実は、Protocol Buffer には Well-Known Types という組み込み型が定義されていまして、 Timestampも存在しています。 このため、上記のように Well-known Types の型定義を .proto ファイル上で import してやれば、Protocol Buffer 上で時刻が扱えるようになります。

この TimeStamp 型の実際の定義は timestamp.proto に存在しますが、UNIX の epoch time とナノ秒を保持しているだけです。golang だと ptypes を使うことで、time.Timestring への変換も可能です。

message Timestamp {
  int64 seconds = 1;
  int32 nanos = 2;
}

あるいは、string として定義する

TimeStamp 型は扱いづらい、Scalar が良い、というのであれば、string として定義しても良いと思います。 protocol buffer をやり取りするピア間で、フォーマットさえ合意しておけば問題にはならないと考えています。

実は、直近ではこちらの方法を採っていまして、RFC 3339 形式で表すようにしています。

int64 で定義する

秒の粒度しか使わないのであれば、 int64 で epoch time として定義しても良いんじゃないか。Timestamp 型も結局のところ epoch time だし。

string の話含め、timestamp という型情報が失われるのをどう見るか。

時刻は要らない、日付だけ扱いたい

Google でも自分で定義しているので、自分で定義したほうが良いのではないでしょうか。 基本的な型については https://github.com/googleapis/googleapis/tree/master/google/type 配下が参考になります。

message Date {
    int32 year = 1;
    int32 month = 2;
    int32 day = 3;
}