duration.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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. package ptypes
  5. // This file implements conversions between google.protobuf.Duration
  6. // and time.Duration.
  7. import (
  8. "errors"
  9. "fmt"
  10. "time"
  11. durpb "github.com/golang/protobuf/ptypes/duration"
  12. )
  13. const (
  14. // Range of a durpb.Duration in seconds, as specified in
  15. // google/protobuf/duration.proto. This is about 10,000 years in seconds.
  16. maxSeconds = int64(10000 * 365.25 * 24 * 60 * 60)
  17. minSeconds = -maxSeconds
  18. )
  19. // validateDuration determines whether the durpb.Duration is valid according to the
  20. // definition in google/protobuf/duration.proto. A valid durpb.Duration
  21. // may still be too large to fit into a time.Duration (the range of durpb.Duration
  22. // is about 10,000 years, and the range of time.Duration is about 290).
  23. func validateDuration(d *durpb.Duration) error {
  24. if d == nil {
  25. return errors.New("duration: nil Duration")
  26. }
  27. if d.Seconds < minSeconds || d.Seconds > maxSeconds {
  28. return fmt.Errorf("duration: %v: seconds out of range", d)
  29. }
  30. if d.Nanos <= -1e9 || d.Nanos >= 1e9 {
  31. return fmt.Errorf("duration: %v: nanos out of range", d)
  32. }
  33. // Seconds and Nanos must have the same sign, unless d.Nanos is zero.
  34. if (d.Seconds < 0 && d.Nanos > 0) || (d.Seconds > 0 && d.Nanos < 0) {
  35. return fmt.Errorf("duration: %v: seconds and nanos have different signs", d)
  36. }
  37. return nil
  38. }
  39. // Duration converts a durpb.Duration to a time.Duration. Duration
  40. // returns an error if the durpb.Duration is invalid or is too large to be
  41. // represented in a time.Duration.
  42. func Duration(p *durpb.Duration) (time.Duration, error) {
  43. if err := validateDuration(p); err != nil {
  44. return 0, err
  45. }
  46. d := time.Duration(p.Seconds) * time.Second
  47. if int64(d/time.Second) != p.Seconds {
  48. return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
  49. }
  50. if p.Nanos != 0 {
  51. d += time.Duration(p.Nanos) * time.Nanosecond
  52. if (d < 0) != (p.Nanos < 0) {
  53. return 0, fmt.Errorf("duration: %v is out of range for time.Duration", p)
  54. }
  55. }
  56. return d, nil
  57. }
  58. // DurationProto converts a time.Duration to a durpb.Duration.
  59. func DurationProto(d time.Duration) *durpb.Duration {
  60. nanos := d.Nanoseconds()
  61. secs := nanos / 1e9
  62. nanos -= secs * 1e9
  63. return &durpb.Duration{
  64. Seconds: secs,
  65. Nanos: int32(nanos),
  66. }
  67. }