blob: 8368a3f70d383262c41321af736849234da34a83 [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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.
khenaidooac637102019-01-14 15:44:34 -05004
5package ptypes
6
khenaidooac637102019-01-14 15:44:34 -05007import (
8 "errors"
9 "fmt"
10 "time"
11
khenaidood948f772021-08-11 17:49:24 -040012 timestamppb "github.com/golang/protobuf/ptypes/timestamp"
khenaidooac637102019-01-14 15:44:34 -050013)
14
khenaidood948f772021-08-11 17:49:24 -040015// Range of google.protobuf.Duration as specified in timestamp.proto.
khenaidooac637102019-01-14 15:44:34 -050016const (
17 // Seconds field of the earliest valid Timestamp.
18 // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
19 minValidSeconds = -62135596800
20 // Seconds field just after the latest valid Timestamp.
21 // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix().
22 maxValidSeconds = 253402300800
23)
24
khenaidood948f772021-08-11 17:49:24 -040025// Timestamp converts a timestamppb.Timestamp to a time.Time.
26// It returns an error if the argument is invalid.
27//
28// Unlike most Go functions, if Timestamp returns an error, the first return
29// value is not the zero time.Time. Instead, it is the value obtained from the
30// time.Unix function when passed the contents of the Timestamp, in the UTC
31// locale. This may or may not be a meaningful time; many invalid Timestamps
32// do map to valid time.Times.
33//
34// A nil Timestamp returns an error. The first return value in that case is
35// undefined.
36//
37// Deprecated: Call the ts.AsTime and ts.CheckValid methods instead.
38func Timestamp(ts *timestamppb.Timestamp) (time.Time, error) {
39 // Don't return the zero value on error, because corresponds to a valid
40 // timestamp. Instead return whatever time.Unix gives us.
41 var t time.Time
42 if ts == nil {
43 t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp
44 } else {
45 t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC()
46 }
47 return t, validateTimestamp(ts)
48}
49
50// TimestampNow returns a google.protobuf.Timestamp for the current time.
51//
52// Deprecated: Call the timestamppb.Now function instead.
53func TimestampNow() *timestamppb.Timestamp {
54 ts, err := TimestampProto(time.Now())
55 if err != nil {
56 panic("ptypes: time.Now() out of Timestamp range")
57 }
58 return ts
59}
60
61// TimestampProto converts the time.Time to a google.protobuf.Timestamp proto.
62// It returns an error if the resulting Timestamp is invalid.
63//
64// Deprecated: Call the timestamppb.New function instead.
65func TimestampProto(t time.Time) (*timestamppb.Timestamp, error) {
66 ts := &timestamppb.Timestamp{
67 Seconds: t.Unix(),
68 Nanos: int32(t.Nanosecond()),
69 }
70 if err := validateTimestamp(ts); err != nil {
71 return nil, err
72 }
73 return ts, nil
74}
75
76// TimestampString returns the RFC 3339 string for valid Timestamps.
77// For invalid Timestamps, it returns an error message in parentheses.
78//
79// Deprecated: Call the ts.AsTime method instead,
80// followed by a call to the Format method on the time.Time value.
81func TimestampString(ts *timestamppb.Timestamp) string {
82 t, err := Timestamp(ts)
83 if err != nil {
84 return fmt.Sprintf("(%v)", err)
85 }
86 return t.Format(time.RFC3339Nano)
87}
88
khenaidooac637102019-01-14 15:44:34 -050089// validateTimestamp determines whether a Timestamp is valid.
khenaidood948f772021-08-11 17:49:24 -040090// A valid timestamp represents a time in the range [0001-01-01, 10000-01-01)
91// and has a Nanos field in the range [0, 1e9).
khenaidooac637102019-01-14 15:44:34 -050092//
93// If the Timestamp is valid, validateTimestamp returns nil.
khenaidood948f772021-08-11 17:49:24 -040094// Otherwise, it returns an error that describes the problem.
khenaidooac637102019-01-14 15:44:34 -050095//
khenaidood948f772021-08-11 17:49:24 -040096// Every valid Timestamp can be represented by a time.Time,
97// but the converse is not true.
98func validateTimestamp(ts *timestamppb.Timestamp) error {
khenaidooac637102019-01-14 15:44:34 -050099 if ts == nil {
100 return errors.New("timestamp: nil Timestamp")
101 }
102 if ts.Seconds < minValidSeconds {
103 return fmt.Errorf("timestamp: %v before 0001-01-01", ts)
104 }
105 if ts.Seconds >= maxValidSeconds {
106 return fmt.Errorf("timestamp: %v after 10000-01-01", ts)
107 }
108 if ts.Nanos < 0 || ts.Nanos >= 1e9 {
109 return fmt.Errorf("timestamp: %v: nanos not in range [0, 1e9)", ts)
110 }
111 return nil
112}