// Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ptypes import ( "errors" "fmt" "time" durationpb "github.com/golang/protobuf/ptypes/duration" ) // Range of google.protobuf.Duration as specified in duration.proto. // This is about 10,000 years in seconds. const ( maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) minSeconds = -maxSeconds ) // Duration converts a durationpb.Duration to a time.Duration. // Duration returns an error if dur is invalid or overflows a 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 converts a time.Duration to a 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 determines whether the durationpb.Duration is valid // according to the definition in google/protobuf/duration.proto. // A valid durpb.Duration may still be too large to fit into a time.Duration // Note that the range of durationpb.Duration is about 10,000 years, // while the range of time.Duration is about 290 years. 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) } // Seconds and Nanos must have the same sign, unless d.Nanos is zero. 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 }