【源码阅读】protobuf 中的 duration 包

文章目录

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
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值