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. 24// 25// Deprecated: Call the dur.AsDuration and dur.CheckValid methods instead. 26func Duration(dur *durationpb.Duration) (time.Duration, error) { 27 if err := validateDuration(dur); err != nil { 28 return 0, err 29 } 30 d := time.Duration(dur.Seconds) * time.Second 31 if int64(d/time.Second) != dur.Seconds { 32 return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) 33 } 34 if dur.Nanos != 0 { 35 d += time.Duration(dur.Nanos) * time.Nanosecond 36 if (d < 0) != (dur.Nanos < 0) { 37 return 0, fmt.Errorf("duration: %v is out of range for time.Duration", dur) 38 } 39 } 40 return d, nil 41} 42 43// DurationProto converts a time.Duration to a durationpb.Duration. 44// 45// Deprecated: Call the durationpb.New function instead. 46func DurationProto(d time.Duration) *durationpb.Duration { 47 nanos := d.Nanoseconds() 48 secs := nanos / 1e9 49 nanos -= secs * 1e9 50 return &durationpb.Duration{ 51 Seconds: int64(secs), 52 Nanos: int32(nanos), 53 } 54} 55 56// validateDuration determines whether the durationpb.Duration is valid 57// according to the definition in google/protobuf/duration.proto. 58// A valid durpb.Duration may still be too large to fit into a time.Duration 59// Note that the range of durationpb.Duration is about 10,000 years, 60// while the range of time.Duration is about 290 years. 61func validateDuration(dur *durationpb.Duration) error { 62 if dur == nil { 63 return errors.New("duration: nil Duration") 64 } 65 if dur.Seconds < minSeconds || dur.Seconds > maxSeconds { 66 return fmt.Errorf("duration: %v: seconds out of range", dur) 67 } 68 if dur.Nanos <= -1e9 || dur.Nanos >= 1e9 { 69 return fmt.Errorf("duration: %v: nanos out of range", dur) 70 } 71 // Seconds and Nanos must have the same sign, unless d.Nanos is zero. 72 if (dur.Seconds < 0 && dur.Nanos > 0) || (dur.Seconds > 0 && dur.Nanos < 0) { 73 return fmt.Errorf("duration: %v: seconds and nanos have different signs", dur) 74 } 75 return nil 76} 77