文章目录
Duration
path: google/protobuf/duration.proto
在 duration 中 Duration 包含两个字段
seconds 表示时间跨度,允许的值范围是从 -315,576,000,000 到 +315,576,000,000
即已 60 秒/分 * 60 分/小时 * 24 小时/天 * 365.25 天/年 * 10000 年 计算出来的值nanos 表示时间跨度的纳秒,允许的值范围是从 -999,999,999 到 +999,999,999
且 nanos 字段的正负必须与 seconds 字段保持一致
message Duration {
int64 seconds = 1;
int32 nanos = 2;
}
duration.go
path: github.com/golang/protobuf/ptypes/duration.go
package ptypes
import (
"errors"
"fmt"
"time"
durationpb "github.com/golang/protobuf/ptypes/duration"
)
// 定义 google.protobuf.Duration 在 duration.proto 中的取值范围
// 最大值是 10,000 年以秒计算的整型
// 最小值也是 10,000 年以秒计算的整型,取负值
const (
maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
minSeconds = -maxSeconds
)
// 函数 Duration 将 *durationpb.Duration 类型的值转化为 time.Duration 类型的值
// 如果参数不是合法的 *durationpb.Duration 或者超出了 time.Duration 的返回,则返回错误
func Duration(dur *durationpb.Duration) (time.Duration, error) {
if err := validateDuration(dur); err != nil {
return 0, err
}
d := time.Duration(dur.Seconds) * time.Second
if int64(d/time.Second) != dur.Seconds {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
}
if dur.Nanos != 0 {
d += time.Duration(dur.Nanos) * time.Nanosecond
if (d < 0) != (dur.Nanos < 0) {
return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur)
}
}
return d, nil
}
// 函数 DurationProto 将 time.Duration 类型转换为 *durationpb.Duration 类型
func DurationProto(d time.Duration) *durationpb.Duration {
nanos := d.Nanoseconds()
secs := nanos / 1e9
nanos -= secs * 1e9
return &durationpb.Duration{
Seconds: int64(secs),
Nanos: int32(nanos),
}
}
// 函数 validateDuration 通过`google/protobuf/duration.proto`中的定义,来验证参数 dur 是否是合法的 *durationpb.Duration
// 由于 durationpb.Duration 的取值返回与 time.Duration 的取值范围的差异,导致 durationpb.Duration 超出 time.Duration 所能容纳的范围
// 当 durationpb.Duration 的取值范围是正负 10,000 年
// 而 time.Duration 的取值范围是正负 290 年
func validateDuration(dur *durationpb.Duration) error {
if dur == nil {
return errors.New("duration: nil Duration")
}
if dur.Seconds < minSeconds || dur.Seconds > maxSeconds {
return fmt.Errorf("duration: %v: seconds out of range", dur)
}
if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 {
return fmt.Errorf("duration: %v: nanos out of range", dur)
}
if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) {
return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur)
}
return nil
}