1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package ptypes 6 7import ( 8 "errors" 9 "fmt" 10 "time" 11 12 durationpb "github.com/golang/protobuf/ptypes/duration" 13) 14 15// Range of google.protobuf.Duration as specified in duration.proto. 16// This is about 10,000 years in seconds. 17const ( 18 maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60) 19 minSeconds = -maxSeconds 20) 21 22// Duration converts a durationpb.Duration to a time.Duration. 23// Duration returns an error if dur is invalid or overflows a time.Duration. 24func Duration(dur *durationpb.Duration) (time.Duration, error) { 25 if err := validateDuration(dur); err != nil { 26 return 0, err 27 } 28 d := time.Duration(dur.Seconds) * time.Second 29 if int64(d/time.Second) != dur.Seconds { 30 return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) 31 } 32 if dur.Nanos != 0 { 33 d += time.Duration(dur.Nanos) * time.Nanosecond 34 if (d < 0) != (dur.Nanos < 0) { 35 return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) 36 } 37 } 38 return d, nil 39} 40 41// DurationProto converts a time.Duration to a durationpb.Duration. 42func DurationProto(d time.Duration) *durationpb.Duration { 43 nanos := d.Nanoseconds() 44 secs := nanos / 1e9 45 nanos -= secs * 1e9 46 return &durationpb.Duration{ 47 Seconds: int64(secs), 48 Nanos: int32(nanos), 49 } 50} 51 52// validateDuration determines whether the durationpb.Duration is valid 53// according to the definition in google/protobuf/duration.proto. 54// A valid durpb.Duration may still be too large to fit into a time.Duration 55// Note that the range of durationpb.Duration is about 10,000 years, 56// while the range of time.Duration is about 290 years. 57func validateDuration(dur *durationpb.Duration) error { 58 if dur == nil { 59 return errors.New("duration: nil Duration") 60 } 61 if dur.Seconds < minSeconds || dur.Seconds > maxSeconds { 62 return fmt.Errorf("duration: %v: seconds out of range", dur) 63 } 64 if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 { 65 return fmt.Errorf("duration: %v: nanos out of range", dur) 66 } 67 // Seconds and Nanos must have the same sign, unless d.Nanos is zero. 68 if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) { 69 return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur) 70 } 71 return nil 72} 73