github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logproto/timestamp.go (about) 1 package logproto 2 3 import ( 4 "errors" 5 strconv "strconv" 6 time "time" 7 8 "github.com/gogo/protobuf/types" 9 ) 10 11 const ( 12 // Seconds field of the earliest valid Timestamp. 13 // This is time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). 14 minValidSeconds = -62135596800 15 // Seconds field just after the latest valid Timestamp. 16 // This is time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Unix(). 17 maxValidSeconds = 253402300800 18 ) 19 20 // validateTimestamp determines whether a Timestamp is valid. 21 // A valid timestamp represents a time in the range 22 // [0001-01-01, 10000-01-01) and has a Nanos field 23 // in the range [0, 1e9). 24 // 25 // If the Timestamp is valid, validateTimestamp returns nil. 26 // Otherwise, it returns an error that describes 27 // the problem. 28 // 29 // Every valid Timestamp can be represented by a time.Time, but the converse is not true. 30 func validateTimestamp(ts *types.Timestamp) error { 31 if ts == nil { 32 return errors.New("timestamp: nil Timestamp") 33 } 34 if ts.Seconds < minValidSeconds { 35 return errors.New("timestamp: " + formatTimestamp(ts) + " before 0001-01-01") 36 } 37 if ts.Seconds >= maxValidSeconds { 38 return errors.New("timestamp: " + formatTimestamp(ts) + " after 10000-01-01") 39 } 40 if ts.Nanos < 0 || ts.Nanos >= 1e9 { 41 return errors.New("timestamp: " + formatTimestamp(ts) + ": nanos not in range [0, 1e9)") 42 } 43 return nil 44 } 45 46 // formatTimestamp is equivalent to fmt.Sprintf("%#v", ts) 47 // but avoids the escape incurred by using fmt.Sprintf, eliminating 48 // unnecessary heap allocations. 49 func formatTimestamp(ts *types.Timestamp) string { 50 if ts == nil { 51 return "nil" 52 } 53 54 seconds := strconv.FormatInt(ts.Seconds, 10) 55 nanos := strconv.FormatInt(int64(ts.Nanos), 10) 56 return "&types.Timestamp{Seconds: " + seconds + ",\nNanos: " + nanos + ",\n}" 57 } 58 59 func SizeOfStdTime(t time.Time) int { 60 ts, err := timestampProto(t) 61 if err != nil { 62 return 0 63 } 64 return ts.Size() 65 } 66 67 func StdTimeMarshalTo(t time.Time, data []byte) (int, error) { 68 ts, err := timestampProto(t) 69 if err != nil { 70 return 0, err 71 } 72 return ts.MarshalTo(data) 73 } 74 75 func StdTimeUnmarshal(t *time.Time, data []byte) error { 76 ts := &types.Timestamp{} 77 if err := ts.Unmarshal(data); err != nil { 78 return err 79 } 80 tt, err := timestampFromProto(ts) 81 if err != nil { 82 return err 83 } 84 *t = tt 85 return nil 86 } 87 88 func timestampFromProto(ts *types.Timestamp) (time.Time, error) { 89 // Don't return the zero value on error, because corresponds to a valid 90 // timestamp. Instead return whatever time.Unix gives us. 91 var t time.Time 92 if ts == nil { 93 t = time.Unix(0, 0).UTC() // treat nil like the empty Timestamp 94 } else { 95 t = time.Unix(ts.Seconds, int64(ts.Nanos)).UTC() 96 } 97 return t, validateTimestamp(ts) 98 } 99 100 func timestampProto(t time.Time) (types.Timestamp, error) { 101 ts := types.Timestamp{ 102 Seconds: t.Unix(), 103 Nanos: int32(t.Nanosecond()), 104 } 105 return ts, validateTimestamp(&ts) 106 }