/proc/self/cwd/internal/time.cc
Line | Count | Source |
1 | | // Copyright 2021 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include "internal/time.h" |
16 | | |
17 | | #include <cstdint> |
18 | | #include <string> |
19 | | |
20 | | #include "absl/status/status.h" |
21 | | #include "absl/status/statusor.h" |
22 | | #include "absl/strings/str_cat.h" |
23 | | #include "absl/strings/str_format.h" |
24 | | #include "absl/strings/string_view.h" |
25 | | #include "absl/time/time.h" |
26 | | #include "internal/status_macros.h" |
27 | | #include "google/protobuf/util/time_util.h" |
28 | | |
29 | | namespace cel::internal { |
30 | | |
31 | | namespace { |
32 | | |
33 | 0 | std::string RawFormatTimestamp(absl::Time timestamp) { |
34 | 0 | return absl::FormatTime("%Y-%m-%d%ET%H:%M:%E*SZ", timestamp, |
35 | 0 | absl::UTCTimeZone()); |
36 | 0 | } |
37 | | |
38 | | } // namespace |
39 | | |
40 | 0 | absl::Duration MaxDuration() { |
41 | | // This currently supports a larger range then the current CEL spec. The |
42 | | // intent is to widen the CEL spec to support the larger range and match |
43 | | // google.protobuf.Duration from protocol buffer messages, which this |
44 | | // implementation currently supports. |
45 | | // TODO(google/cel-spec/issues/214): revisit |
46 | 0 | return absl::Seconds(google::protobuf::util::TimeUtil::kDurationMaxSeconds) + |
47 | 0 | absl::Nanoseconds(google::protobuf::util::TimeUtil::kDurationMaxNanoseconds); |
48 | 0 | } |
49 | | |
50 | 0 | absl::Duration MinDuration() { |
51 | | // This currently supports a larger range then the current CEL spec. The |
52 | | // intent is to widen the CEL spec to support the larger range and match |
53 | | // google.protobuf.Duration from protocol buffer messages, which this |
54 | | // implementation currently supports. |
55 | | // TODO(google/cel-spec/issues/214): revisit |
56 | 0 | return absl::Seconds(google::protobuf::util::TimeUtil::kDurationMinSeconds) + |
57 | 0 | absl::Nanoseconds(google::protobuf::util::TimeUtil::kDurationMinNanoseconds); |
58 | 0 | } |
59 | | |
60 | 0 | absl::Time MaxTimestamp() { |
61 | 0 | return absl::UnixEpoch() + |
62 | 0 | absl::Seconds(google::protobuf::util::TimeUtil::kTimestampMaxSeconds) + |
63 | 0 | absl::Nanoseconds(google::protobuf::util::TimeUtil::kTimestampMaxNanoseconds); |
64 | 0 | } |
65 | | |
66 | 0 | absl::Time MinTimestamp() { |
67 | 0 | return absl::UnixEpoch() + |
68 | 0 | absl::Seconds(google::protobuf::util::TimeUtil::kTimestampMinSeconds) + |
69 | 0 | absl::Nanoseconds(google::protobuf::util::TimeUtil::kTimestampMinNanoseconds); |
70 | 0 | } |
71 | | |
72 | 0 | absl::Status ValidateDuration(absl::Duration duration) { |
73 | 0 | if (duration < MinDuration()) { |
74 | 0 | return absl::InvalidArgumentError( |
75 | 0 | absl::StrCat("Duration \"", absl::FormatDuration(duration), |
76 | 0 | "\" below minimum allowed duration \"", |
77 | 0 | absl::FormatDuration(MinDuration()), "\"")); |
78 | 0 | } |
79 | 0 | if (duration > MaxDuration()) { |
80 | 0 | return absl::InvalidArgumentError( |
81 | 0 | absl::StrCat("Duration \"", absl::FormatDuration(duration), |
82 | 0 | "\" above maximum allowed duration \"", |
83 | 0 | absl::FormatDuration(MaxDuration()), "\"")); |
84 | 0 | } |
85 | 0 | return absl::OkStatus(); |
86 | 0 | } |
87 | | |
88 | 0 | absl::StatusOr<absl::Duration> ParseDuration(absl::string_view input) { |
89 | 0 | absl::Duration duration; |
90 | 0 | if (!absl::ParseDuration(input, &duration)) { |
91 | 0 | return absl::InvalidArgumentError("Failed to parse duration from string"); |
92 | 0 | } |
93 | 0 | return duration; |
94 | 0 | } |
95 | | |
96 | 0 | absl::StatusOr<std::string> FormatDuration(absl::Duration duration) { |
97 | 0 | CEL_RETURN_IF_ERROR(ValidateDuration(duration)); |
98 | 0 | return absl::FormatDuration(duration); |
99 | 0 | } |
100 | | |
101 | 0 | std::string DebugStringDuration(absl::Duration duration) { |
102 | 0 | return absl::FormatDuration(duration); |
103 | 0 | } |
104 | | |
105 | 0 | absl::Status ValidateTimestamp(absl::Time timestamp) { |
106 | 0 | if (timestamp < MinTimestamp()) { |
107 | 0 | return absl::InvalidArgumentError( |
108 | 0 | absl::StrCat("Timestamp \"", RawFormatTimestamp(timestamp), |
109 | 0 | "\" below minimum allowed timestamp \"", |
110 | 0 | RawFormatTimestamp(MinTimestamp()), "\"")); |
111 | 0 | } |
112 | 0 | if (timestamp > MaxTimestamp()) { |
113 | 0 | return absl::InvalidArgumentError( |
114 | 0 | absl::StrCat("Timestamp \"", RawFormatTimestamp(timestamp), |
115 | 0 | "\" above maximum allowed timestamp \"", |
116 | 0 | RawFormatTimestamp(MaxTimestamp()), "\"")); |
117 | 0 | } |
118 | 0 | return absl::OkStatus(); |
119 | 0 | } |
120 | | |
121 | 0 | absl::StatusOr<absl::Time> ParseTimestamp(absl::string_view input) { |
122 | 0 | absl::Time timestamp; |
123 | 0 | std::string err; |
124 | 0 | if (!absl::ParseTime(absl::RFC3339_full, input, absl::UTCTimeZone(), |
125 | 0 | ×tamp, &err)) { |
126 | 0 | return err.empty() ? absl::InvalidArgumentError( |
127 | 0 | "Failed to parse timestamp from string") |
128 | 0 | : absl::InvalidArgumentError(absl::StrCat( |
129 | 0 | "Failed to parse timestamp from string: ", err)); |
130 | 0 | } |
131 | 0 | CEL_RETURN_IF_ERROR(ValidateTimestamp(timestamp)); |
132 | 0 | return timestamp; |
133 | 0 | } |
134 | | |
135 | 0 | absl::StatusOr<std::string> FormatTimestamp(absl::Time timestamp) { |
136 | 0 | CEL_RETURN_IF_ERROR(ValidateTimestamp(timestamp)); |
137 | 0 | return RawFormatTimestamp(timestamp); |
138 | 0 | } |
139 | | |
140 | 0 | std::string FormatNanos(int32_t nanos) { |
141 | 0 | constexpr int32_t kNanosPerMillisecond = 1000000; |
142 | 0 | constexpr int32_t kNanosPerMicrosecond = 1000; |
143 | |
|
144 | 0 | if (nanos % kNanosPerMillisecond == 0) { |
145 | 0 | return absl::StrFormat("%03d", nanos / kNanosPerMillisecond); |
146 | 0 | } else if (nanos % kNanosPerMicrosecond == 0) { |
147 | 0 | return absl::StrFormat("%06d", nanos / kNanosPerMicrosecond); |
148 | 0 | } |
149 | 0 | return absl::StrFormat("%09d", nanos); |
150 | 0 | } |
151 | | |
152 | 0 | absl::StatusOr<std::string> EncodeDurationToJson(absl::Duration duration) { |
153 | | // Adapted from protobuf time_util. |
154 | 0 | CEL_RETURN_IF_ERROR(ValidateDuration(duration)); |
155 | 0 | std::string result; |
156 | 0 | int64_t seconds = absl::IDivDuration(duration, absl::Seconds(1), &duration); |
157 | 0 | int64_t nanos = absl::IDivDuration(duration, absl::Nanoseconds(1), &duration); |
158 | |
|
159 | 0 | if (seconds < 0 || nanos < 0) { |
160 | 0 | result = "-"; |
161 | 0 | seconds = -seconds; |
162 | 0 | nanos = -nanos; |
163 | 0 | } |
164 | |
|
165 | 0 | absl::StrAppend(&result, seconds); |
166 | 0 | if (nanos != 0) { |
167 | 0 | absl::StrAppend(&result, ".", FormatNanos(nanos)); |
168 | 0 | } |
169 | |
|
170 | 0 | absl::StrAppend(&result, "s"); |
171 | 0 | return result; |
172 | 0 | } |
173 | | |
174 | 0 | absl::StatusOr<std::string> EncodeTimestampToJson(absl::Time timestamp) { |
175 | | // Adapted from protobuf time_util. |
176 | 0 | static constexpr absl::string_view kTimestampFormat = "%E4Y-%m-%dT%H:%M:%S"; |
177 | 0 | CEL_RETURN_IF_ERROR(ValidateTimestamp(timestamp)); |
178 | | // Handle nanos and the seconds separately to match proto JSON format. |
179 | 0 | absl::Time unix_seconds = |
180 | 0 | absl::FromUnixSeconds(absl::ToUnixSeconds(timestamp)); |
181 | 0 | int64_t n = (timestamp - unix_seconds) / absl::Nanoseconds(1); |
182 | |
|
183 | 0 | std::string result = |
184 | 0 | absl::FormatTime(kTimestampFormat, unix_seconds, absl::UTCTimeZone()); |
185 | |
|
186 | 0 | if (n > 0) { |
187 | 0 | absl::StrAppend(&result, ".", FormatNanos(n)); |
188 | 0 | } |
189 | |
|
190 | 0 | absl::StrAppend(&result, "Z"); |
191 | 0 | return result; |
192 | 0 | } |
193 | | |
194 | 0 | std::string DebugStringTimestamp(absl::Time timestamp) { |
195 | 0 | return RawFormatTimestamp(timestamp); |
196 | 0 | } |
197 | | |
198 | | } // namespace cel::internal |