You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

133 lines
4.7 KiB

  1. // Go support for Protocol Buffers - Google's data interchange format
  2. //
  3. // Copyright 2016 The Go Authors. All rights reserved.
  4. // https://github.com/golang/protobuf
  5. //
  6. // Redistribution and use in source and binary forms, with or without
  7. // modification, are permitted provided that the following conditions are
  8. // met:
  9. //
  10. // * Redistributions of source code must retain the above copyright
  11. // notice, this list of conditions and the following disclaimer.
  12. // * Redistributions in binary form must reproduce the above
  13. // copyright notice, this list of conditions and the following disclaimer
  14. // in the documentation and/or other materials provided with the
  15. // distribution.
  16. // * Neither the name of Google Inc. nor the names of its
  17. // contributors may be used to endorse or promote products derived from
  18. // this software without specific prior written permission.
  19. //
  20. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. package ptypes
  32. // This file implements operations on google.protobuf.Timestamp.
  33. import (
  34. "errors"
  35. "fmt"
  36. "time"
  37. tspb "github.com/golang/protobuf/ptypes/timestamp"
  38. )
  39. const (
  40. // Seconds field of the earliest valid Timestamp.
  41. // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
  42. minValidSeconds = -62135596800
  43. // Seconds field just after the latest valid Timestamp.
  44. // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
  45. maxValidSeconds = 253402300800
  46. )
  47. // validateTimestamp determines whether a Timestamp is valid.
  48. // A valid timestamp represents a time in the range
  49. // [0001-01-01, 10000-01-01) and has a Nanos field
  50. // in the range [0, 1e9).
  51. //
  52. // If the Timestamp is valid, validateTimestamp returns nil.
  53. // Otherwise, it returns an error that describes
  54. // the problem.
  55. //
  56. // Every valid Timestamp can be represented by a time.Time, but the converse is not true.
  57. func validateTimestamp(ts *tspb.Timestamp) error {
  58. if ts == nil {
  59. return errors.New("timestamp: nil Timestamp")
  60. }
  61. if ts.Seconds < minValidSeconds {
  62. return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
  63. }
  64. if ts.Seconds >= maxValidSeconds {
  65. return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
  66. }
  67. if ts.Nanos < 0 || ts.Nanos >= 1e9 {
  68. return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
  69. }
  70. return nil
  71. }
  72. // Timestamp converts a google.protobuf.Timestamp proto to a time.Time.
  73. // It returns an error if the argument is invalid.
  74. //
  75. // Unlike most Go functions, if Timestamp returns an error, the first return value
  76. // is not the zero time.Time. Instead, it is the value obtained from the
  77. // time.Unix function when passed the contents of the Timestamp, in the UTC
  78. // locale. This may or may not be a meaningful time; many invalid Timestamps
  79. // do map to valid time.Times.
  80. //
  81. // A nil Timestamp returns an error. The first return value in that case is
  82. // undefined.
  83. func Timestamp(ts *tspb.Timestamp) (time.Time, error) {
  84. // Don't return the zero value on error, because corresponds to a valid
  85. // timestamp. Instead return whatever time.Unix gives us.
  86. var t time.Time
  87. if ts == nil {
  88. t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
  89. } else {
  90. t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
  91. }
  92. return t, validateTimestamp(ts)
  93. }
  94. // TimestampNow returns a google.protobuf.Timestamp for the current time.
  95. func TimestampNow() *tspb.Timestamp {
  96. ts, err := TimestampProto(time.Now())
  97. if err != nil {
  98. panic("ptypes: time.Now() out of Timestamp range")
  99. }
  100. return ts
  101. }
  102. // TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
  103. // It returns an error if the resulting Timestamp is invalid.
  104. func TimestampProto(t time.Time) (*tspb.Timestamp, error) {
  105. ts := &tspb.Timestamp{
  106. Seconds: t.Unix(),
  107. Nanos: int32(t.Nanosecond()),
  108. }
  109. if err := validateTimestamp(ts); err != nil {
  110. return nil, err
  111. }
  112. return ts, nil
  113. }
  114. // TimestampString returns the RFC 3339 string for valid Timestamps. For invalid
  115. // Timestamps, it returns an error message in parentheses.
  116. func TimestampString(ts *tspb.Timestamp) string {
  117. t, err := Timestamp(ts)
  118. if err != nil {
  119. return fmt.Sprintf("(%v)", err)
  120. }
  121. return t.Format(time.RFC3339Nano)
  122. }