自从开始在
go
中使用协议缓冲区以来,我考虑了通过 timestamppb.Timestamp
将 time.Time
结构转换为
ptypes.Timestamp
结构的惯用方法,例如:
t, err := ptypes.Timestamp(pbTimestamp)
if err != nil {
// some error handling
}
但是,正如我刚刚发现的,
timestamppb.Timestamp
还有成员函数AsTime
,它可以促进相同的转换,但只返回time.Time
值,而不返回error
。
由于
ptypes.Timestamp
确实在time.Time
之上返回错误,这表明存在失败的可能性,我想知道AsTime
的使用是否可以被认为是安全的。从 godocs 来看,似乎没有什么需要考虑的,但是没有返回转换错误似乎有点奇怪。有没有人对此有任何解释?
tl;dr 你不能跳过验证检查。
这里的问题是由零值的语义差异引起的。
time.Time
值:[...] 是 1 年 1 月 1 日 00:00:00.000000000 UTC。由于这个时间在实践中不太可能出现,IsZero 方法提供了一种简单的方法来检测尚未显式初始化的时间。
timestamppb.Timestamp
是零纪元,即 UTC 时间 1970 年 1 月 1 日午夜。这意味着零
timestamppb.Timestamp
映射到有效的非零 time.Time
。事实上:
(*timestamppb.Timestamp)(nil).AsTime().IsZero() // FALSE!
而:
timestamppb.New(time.Time{}).AsTime().IsZero() // true
ptypes.Timestamp
函数可能返回错误的原因。它内置了一个验证步骤,以考虑原始时间戳无效的情况——例如如果是nil
。因此,请勿使用 AsTime
直接替代 ptypes.Timestamp
使用
IsValid
或 CheckValid
代替,然后 AsTime
:
if myProtoTs.IsValid() {
t := myProtoTs.AsTime()
// do something with t
}
进一步阅读,以及原型维护者的评论:https://github.com/golang/protobuf/issues/1457