【源码阅读】protobuf 中的 duration 包

文章目录

      • Duration
      • duration.go

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
}

你可能感兴趣的:(#,protobuf,源码)