1 | // Protocol Buffers - Google's data interchange format |
2 | // Copyright 2008 Google Inc. All rights reserved. |
3 | // https://developers.google.com/protocol-buffers/ |
4 | // |
5 | // Redistribution and use in source and binary forms, with or without |
6 | // modification, are permitted provided that the following conditions are |
7 | // met: |
8 | // |
9 | // * Redistributions of source code must retain the above copyright |
10 | // notice, this list of conditions and the following disclaimer. |
11 | // * Redistributions in binary form must reproduce the above |
12 | // copyright notice, this list of conditions and the following disclaimer |
13 | // in the documentation and/or other materials provided with the |
14 | // distribution. |
15 | // * Neither the name of Google Inc. nor the names of its |
16 | // contributors may be used to endorse or promote products derived from |
17 | // this software without specific prior written permission. |
18 | // |
19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | |
31 | #include <google/protobuf/util/time_util.h> |
32 | |
33 | #include <cstdint> |
34 | |
35 | #include <google/protobuf/stubs/strutil.h> |
36 | #include <google/protobuf/duration.pb.h> |
37 | #include <google/protobuf/timestamp.pb.h> |
38 | #include <google/protobuf/stubs/int128.h> |
39 | #include <google/protobuf/stubs/stringprintf.h> |
40 | #include <google/protobuf/stubs/time.h> |
41 | |
42 | // Must go after other includes. |
43 | #include <google/protobuf/port_def.inc> |
44 | |
45 | namespace google { |
46 | namespace protobuf { |
47 | namespace util { |
48 | |
49 | using google::protobuf::Duration; |
50 | using google::protobuf::Timestamp; |
51 | |
52 | namespace { |
53 | static const int kNanosPerSecond = 1000000000; |
54 | static const int kMicrosPerSecond = 1000000; |
55 | static const int kMillisPerSecond = 1000; |
56 | static const int kNanosPerMillisecond = 1000000; |
57 | static const int kNanosPerMicrosecond = 1000; |
58 | static const int kSecondsPerMinute = 60; // Note that we ignore leap seconds. |
59 | static const int kSecondsPerHour = 3600; |
60 | |
61 | template <typename T> |
62 | T CreateNormalized(int64_t seconds, int64_t nanos); |
63 | |
64 | template <> |
65 | Timestamp CreateNormalized(int64_t seconds, int64_t nanos) { |
66 | // Make sure nanos is in the range. |
67 | if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { |
68 | seconds += nanos / kNanosPerSecond; |
69 | nanos = nanos % kNanosPerSecond; |
70 | } |
71 | // For Timestamp nanos should be in the range [0, 999999999] |
72 | if (nanos < 0) { |
73 | seconds -= 1; |
74 | nanos += kNanosPerSecond; |
75 | } |
76 | GOOGLE_DCHECK(seconds >= TimeUtil::kTimestampMinSeconds && |
77 | seconds <= TimeUtil::kTimestampMaxSeconds); |
78 | Timestamp result; |
79 | result.set_seconds(seconds); |
80 | result.set_nanos(static_cast<int32_t>(nanos)); |
81 | return result; |
82 | } |
83 | |
84 | template <> |
85 | Duration CreateNormalized(int64_t seconds, int64_t nanos) { |
86 | // Make sure nanos is in the range. |
87 | if (nanos <= -kNanosPerSecond || nanos >= kNanosPerSecond) { |
88 | seconds += nanos / kNanosPerSecond; |
89 | nanos = nanos % kNanosPerSecond; |
90 | } |
91 | // nanos should have the same sign as seconds. |
92 | if (seconds < 0 && nanos > 0) { |
93 | seconds += 1; |
94 | nanos -= kNanosPerSecond; |
95 | } else if (seconds > 0 && nanos < 0) { |
96 | seconds -= 1; |
97 | nanos += kNanosPerSecond; |
98 | } |
99 | GOOGLE_DCHECK(seconds >= TimeUtil::kDurationMinSeconds && |
100 | seconds <= TimeUtil::kDurationMaxSeconds); |
101 | Duration result; |
102 | result.set_seconds(seconds); |
103 | result.set_nanos(static_cast<int32_t>(nanos)); |
104 | return result; |
105 | } |
106 | |
107 | // Format nanoseconds with either 3, 6, or 9 digits depending on the required |
108 | // precision to represent the exact value. |
109 | std::string FormatNanos(int32_t nanos) { |
110 | if (nanos % kNanosPerMillisecond == 0) { |
111 | return StringPrintf(format: "%03d" , nanos / kNanosPerMillisecond); |
112 | } else if (nanos % kNanosPerMicrosecond == 0) { |
113 | return StringPrintf(format: "%06d" , nanos / kNanosPerMicrosecond); |
114 | } else { |
115 | return StringPrintf(format: "%09d" , nanos); |
116 | } |
117 | } |
118 | |
119 | std::string FormatTime(int64_t seconds, int32_t nanos) { |
120 | return ::google::protobuf::internal::FormatTime(seconds, nanos); |
121 | } |
122 | |
123 | bool ParseTime(const std::string& value, int64_t* seconds, int32_t* nanos) { |
124 | return ::google::protobuf::internal::ParseTime(value, seconds, nanos); |
125 | } |
126 | |
127 | void CurrentTime(int64_t* seconds, int32_t* nanos) { |
128 | return ::google::protobuf::internal::GetCurrentTime(seconds, nanos); |
129 | } |
130 | |
131 | // Truncates the remainder part after division. |
132 | int64_t RoundTowardZero(int64_t value, int64_t divider) { |
133 | int64_t result = value / divider; |
134 | int64_t remainder = value % divider; |
135 | // Before C++11, the sign of the remainder is implementation dependent if |
136 | // any of the operands is negative. Here we try to enforce C++11's "rounded |
137 | // toward zero" semantics. For example, for (-5) / 2 an implementation may |
138 | // give -3 as the result with the remainder being 1. This function ensures |
139 | // we always return -2 (closer to zero) regardless of the implementation. |
140 | if (result < 0 && remainder > 0) { |
141 | return result + 1; |
142 | } else { |
143 | return result; |
144 | } |
145 | } |
146 | } // namespace |
147 | |
148 | // Actually define these static const integers. Required by C++ standard (but |
149 | // some compilers don't like it). |
150 | #ifndef _MSC_VER |
151 | const int64_t TimeUtil::kTimestampMinSeconds; |
152 | const int64_t TimeUtil::kTimestampMaxSeconds; |
153 | const int64_t TimeUtil::kDurationMaxSeconds; |
154 | const int64_t TimeUtil::kDurationMinSeconds; |
155 | #endif // !_MSC_VER |
156 | |
157 | std::string TimeUtil::ToString(const Timestamp& timestamp) { |
158 | return FormatTime(seconds: timestamp.seconds(), nanos: timestamp.nanos()); |
159 | } |
160 | |
161 | bool TimeUtil::FromString(const std::string& value, Timestamp* timestamp) { |
162 | int64_t seconds; |
163 | int32_t nanos; |
164 | if (!ParseTime(value, seconds: &seconds, nanos: &nanos)) { |
165 | return false; |
166 | } |
167 | *timestamp = CreateNormalized<Timestamp>(seconds, nanos); |
168 | return true; |
169 | } |
170 | |
171 | Timestamp TimeUtil::GetCurrentTime() { |
172 | int64_t seconds; |
173 | int32_t nanos; |
174 | CurrentTime(seconds: &seconds, nanos: &nanos); |
175 | return CreateNormalized<Timestamp>(seconds, nanos); |
176 | } |
177 | |
178 | Timestamp TimeUtil::GetEpoch() { return Timestamp(); } |
179 | |
180 | std::string TimeUtil::ToString(const Duration& duration) { |
181 | std::string result; |
182 | int64_t seconds = duration.seconds(); |
183 | int32_t nanos = duration.nanos(); |
184 | if (seconds < 0 || nanos < 0) { |
185 | result += "-" ; |
186 | seconds = -seconds; |
187 | nanos = -nanos; |
188 | } |
189 | result += StrCat(a: seconds); |
190 | if (nanos != 0) { |
191 | result += "." + FormatNanos(nanos); |
192 | } |
193 | result += "s" ; |
194 | return result; |
195 | } |
196 | |
197 | static int64_t Pow(int64_t x, int y) { |
198 | int64_t result = 1; |
199 | for (int i = 0; i < y; ++i) { |
200 | result *= x; |
201 | } |
202 | return result; |
203 | } |
204 | |
205 | bool TimeUtil::FromString(const std::string& value, Duration* duration) { |
206 | if (value.length() <= 1 || value[value.length() - 1] != 's') { |
207 | return false; |
208 | } |
209 | bool negative = (value[0] == '-'); |
210 | size_t sign_length = (negative ? 1 : 0); |
211 | // Parse the duration value as two integers rather than a float value |
212 | // to avoid precision loss. |
213 | std::string seconds_part, nanos_part; |
214 | size_t pos = value.find_last_of(c: '.'); |
215 | if (pos == std::string::npos) { |
216 | seconds_part = value.substr(pos: sign_length, n: value.length() - 1 - sign_length); |
217 | nanos_part = "0" ; |
218 | } else { |
219 | seconds_part = value.substr(pos: sign_length, n: pos - sign_length); |
220 | nanos_part = value.substr(pos: pos + 1, n: value.length() - pos - 2); |
221 | } |
222 | char* end; |
223 | int64_t seconds = strto64(nptr: seconds_part.c_str(), endptr: &end, base: 10); |
224 | if (end != seconds_part.c_str() + seconds_part.length()) { |
225 | return false; |
226 | } |
227 | int64_t nanos = strto64(nptr: nanos_part.c_str(), endptr: &end, base: 10); |
228 | if (end != nanos_part.c_str() + nanos_part.length()) { |
229 | return false; |
230 | } |
231 | nanos = nanos * Pow(x: 10, y: static_cast<int>(9 - nanos_part.length())); |
232 | if (negative) { |
233 | // If a Duration is negative, both seconds and nanos should be negative. |
234 | seconds = -seconds; |
235 | nanos = -nanos; |
236 | } |
237 | duration->set_seconds(seconds); |
238 | duration->set_nanos(static_cast<int32_t>(nanos)); |
239 | return true; |
240 | } |
241 | |
242 | Duration TimeUtil::NanosecondsToDuration(int64_t nanos) { |
243 | return CreateNormalized<Duration>(seconds: nanos / kNanosPerSecond, |
244 | nanos: nanos % kNanosPerSecond); |
245 | } |
246 | |
247 | Duration TimeUtil::MicrosecondsToDuration(int64_t micros) { |
248 | return CreateNormalized<Duration>( |
249 | seconds: micros / kMicrosPerSecond, |
250 | nanos: (micros % kMicrosPerSecond) * kNanosPerMicrosecond); |
251 | } |
252 | |
253 | Duration TimeUtil::MillisecondsToDuration(int64_t millis) { |
254 | return CreateNormalized<Duration>( |
255 | seconds: millis / kMillisPerSecond, |
256 | nanos: (millis % kMillisPerSecond) * kNanosPerMillisecond); |
257 | } |
258 | |
259 | Duration TimeUtil::SecondsToDuration(int64_t seconds) { |
260 | return CreateNormalized<Duration>(seconds, nanos: 0); |
261 | } |
262 | |
263 | Duration TimeUtil::MinutesToDuration(int64_t minutes) { |
264 | return CreateNormalized<Duration>(seconds: minutes * kSecondsPerMinute, nanos: 0); |
265 | } |
266 | |
267 | Duration TimeUtil::HoursToDuration(int64_t hours) { |
268 | return CreateNormalized<Duration>(seconds: hours * kSecondsPerHour, nanos: 0); |
269 | } |
270 | |
271 | int64_t TimeUtil::DurationToNanoseconds(const Duration& duration) { |
272 | return duration.seconds() * kNanosPerSecond + duration.nanos(); |
273 | } |
274 | |
275 | int64_t TimeUtil::DurationToMicroseconds(const Duration& duration) { |
276 | return duration.seconds() * kMicrosPerSecond + |
277 | RoundTowardZero(value: duration.nanos(), divider: kNanosPerMicrosecond); |
278 | } |
279 | |
280 | int64_t TimeUtil::DurationToMilliseconds(const Duration& duration) { |
281 | return duration.seconds() * kMillisPerSecond + |
282 | RoundTowardZero(value: duration.nanos(), divider: kNanosPerMillisecond); |
283 | } |
284 | |
285 | int64_t TimeUtil::DurationToSeconds(const Duration& duration) { |
286 | return duration.seconds(); |
287 | } |
288 | |
289 | int64_t TimeUtil::DurationToMinutes(const Duration& duration) { |
290 | return RoundTowardZero(value: duration.seconds(), divider: kSecondsPerMinute); |
291 | } |
292 | |
293 | int64_t TimeUtil::DurationToHours(const Duration& duration) { |
294 | return RoundTowardZero(value: duration.seconds(), divider: kSecondsPerHour); |
295 | } |
296 | |
297 | Timestamp TimeUtil::NanosecondsToTimestamp(int64_t nanos) { |
298 | return CreateNormalized<Timestamp>(seconds: nanos / kNanosPerSecond, |
299 | nanos: nanos % kNanosPerSecond); |
300 | } |
301 | |
302 | Timestamp TimeUtil::MicrosecondsToTimestamp(int64_t micros) { |
303 | return CreateNormalized<Timestamp>( |
304 | seconds: micros / kMicrosPerSecond, |
305 | nanos: micros % kMicrosPerSecond * kNanosPerMicrosecond); |
306 | } |
307 | |
308 | Timestamp TimeUtil::MillisecondsToTimestamp(int64_t millis) { |
309 | return CreateNormalized<Timestamp>( |
310 | seconds: millis / kMillisPerSecond, |
311 | nanos: millis % kMillisPerSecond * kNanosPerMillisecond); |
312 | } |
313 | |
314 | Timestamp TimeUtil::SecondsToTimestamp(int64_t seconds) { |
315 | return CreateNormalized<Timestamp>(seconds, nanos: 0); |
316 | } |
317 | |
318 | int64_t TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) { |
319 | return timestamp.seconds() * kNanosPerSecond + timestamp.nanos(); |
320 | } |
321 | |
322 | int64_t TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) { |
323 | return timestamp.seconds() * kMicrosPerSecond + |
324 | RoundTowardZero(value: timestamp.nanos(), divider: kNanosPerMicrosecond); |
325 | } |
326 | |
327 | int64_t TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) { |
328 | return timestamp.seconds() * kMillisPerSecond + |
329 | RoundTowardZero(value: timestamp.nanos(), divider: kNanosPerMillisecond); |
330 | } |
331 | |
332 | int64_t TimeUtil::TimestampToSeconds(const Timestamp& timestamp) { |
333 | return timestamp.seconds(); |
334 | } |
335 | |
336 | Timestamp TimeUtil::TimeTToTimestamp(time_t value) { |
337 | return CreateNormalized<Timestamp>(seconds: static_cast<int64_t>(value), nanos: 0); |
338 | } |
339 | |
340 | time_t TimeUtil::TimestampToTimeT(const Timestamp& value) { |
341 | return static_cast<time_t>(value.seconds()); |
342 | } |
343 | |
344 | Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) { |
345 | return CreateNormalized<Timestamp>(seconds: value.tv_sec, |
346 | nanos: value.tv_usec * kNanosPerMicrosecond); |
347 | } |
348 | |
349 | timeval TimeUtil::TimestampToTimeval(const Timestamp& value) { |
350 | timeval result; |
351 | result.tv_sec = value.seconds(); |
352 | result.tv_usec = RoundTowardZero(value: value.nanos(), divider: kNanosPerMicrosecond); |
353 | return result; |
354 | } |
355 | |
356 | Duration TimeUtil::TimevalToDuration(const timeval& value) { |
357 | return CreateNormalized<Duration>(seconds: value.tv_sec, |
358 | nanos: value.tv_usec * kNanosPerMicrosecond); |
359 | } |
360 | |
361 | timeval TimeUtil::DurationToTimeval(const Duration& value) { |
362 | timeval result; |
363 | result.tv_sec = value.seconds(); |
364 | result.tv_usec = RoundTowardZero(value: value.nanos(), divider: kNanosPerMicrosecond); |
365 | // timeval.tv_usec's range is [0, 1000000) |
366 | if (result.tv_usec < 0) { |
367 | result.tv_sec -= 1; |
368 | result.tv_usec += kMicrosPerSecond; |
369 | } |
370 | return result; |
371 | } |
372 | |
373 | } // namespace util |
374 | } // namespace protobuf |
375 | } // namespace google |
376 | |
377 | namespace google { |
378 | namespace protobuf { |
379 | namespace { |
380 | using ::PROTOBUF_NAMESPACE_ID::util::CreateNormalized; |
381 | using ::PROTOBUF_NAMESPACE_ID::util::kNanosPerSecond; |
382 | |
383 | // Convert a Duration to uint128. |
384 | void ToUint128(const Duration& value, uint128* result, bool* negative) { |
385 | if (value.seconds() < 0 || value.nanos() < 0) { |
386 | *negative = true; |
387 | *result = static_cast<uint64_t>(-value.seconds()); |
388 | *result = *result * kNanosPerSecond + static_cast<uint32_t>(-value.nanos()); |
389 | } else { |
390 | *negative = false; |
391 | *result = static_cast<uint64_t>(value.seconds()); |
392 | *result = *result * kNanosPerSecond + static_cast<uint32_t>(value.nanos()); |
393 | } |
394 | } |
395 | |
396 | void ToDuration(const uint128& value, bool negative, Duration* duration) { |
397 | int64_t seconds = |
398 | static_cast<int64_t>(Uint128Low64(v: value / kNanosPerSecond)); |
399 | int32_t nanos = |
400 | static_cast<int32_t>(Uint128Low64(v: value % kNanosPerSecond)); |
401 | if (negative) { |
402 | seconds = -seconds; |
403 | nanos = -nanos; |
404 | } |
405 | duration->set_seconds(seconds); |
406 | duration->set_nanos(nanos); |
407 | } |
408 | } // namespace |
409 | |
410 | Duration& operator+=(Duration& d1, const Duration& d2) { |
411 | d1 = CreateNormalized<Duration>(seconds: d1.seconds() + d2.seconds(), |
412 | nanos: d1.nanos() + d2.nanos()); |
413 | return d1; |
414 | } |
415 | |
416 | Duration& operator-=(Duration& d1, const Duration& d2) { // NOLINT |
417 | d1 = CreateNormalized<Duration>(seconds: d1.seconds() - d2.seconds(), |
418 | nanos: d1.nanos() - d2.nanos()); |
419 | return d1; |
420 | } |
421 | |
422 | Duration& operator*=(Duration& d, int64_t r) { // NOLINT |
423 | bool negative; |
424 | uint128 value; |
425 | ToUint128(value: d, result: &value, negative: &negative); |
426 | if (r > 0) { |
427 | value *= static_cast<uint64_t>(r); |
428 | } else { |
429 | negative = !negative; |
430 | value *= static_cast<uint64_t>(-r); |
431 | } |
432 | ToDuration(value, negative, duration: &d); |
433 | return d; |
434 | } |
435 | |
436 | Duration& operator*=(Duration& d, double r) { // NOLINT |
437 | double result = |
438 | (static_cast<double>(d.seconds()) + d.nanos() * (1.0 / kNanosPerSecond)) * |
439 | r; |
440 | int64_t seconds = static_cast<int64_t>(result); |
441 | int32_t nanos = static_cast<int32_t>((result - static_cast<double>(seconds)) * |
442 | kNanosPerSecond); |
443 | // Note that we normalize here not just because nanos can have a different |
444 | // sign from seconds but also that nanos can be any arbitrary value when |
445 | // overflow happens (i.e., the result is a much larger value than what |
446 | // int64 can represent). |
447 | d = CreateNormalized<Duration>(seconds, nanos); |
448 | return d; |
449 | } |
450 | |
451 | Duration& operator/=(Duration& d, int64_t r) { // NOLINT |
452 | bool negative; |
453 | uint128 value; |
454 | ToUint128(value: d, result: &value, negative: &negative); |
455 | if (r > 0) { |
456 | value /= static_cast<uint64_t>(r); |
457 | } else { |
458 | negative = !negative; |
459 | value /= static_cast<uint64_t>(-r); |
460 | } |
461 | ToDuration(value, negative, duration: &d); |
462 | return d; |
463 | } |
464 | |
465 | Duration& operator/=(Duration& d, double r) { // NOLINT |
466 | return d *= 1.0 / r; |
467 | } |
468 | |
469 | Duration& operator%=(Duration& d1, const Duration& d2) { // NOLINT |
470 | bool negative1, negative2; |
471 | uint128 value1, value2; |
472 | ToUint128(value: d1, result: &value1, negative: &negative1); |
473 | ToUint128(value: d2, result: &value2, negative: &negative2); |
474 | uint128 result = value1 % value2; |
475 | // When negative values are involved in division, we round the division |
476 | // result towards zero. With this semantics, sign of the remainder is the |
477 | // same as the dividend. For example: |
478 | // -5 / 10 = 0, -5 % 10 = -5 |
479 | // -5 / (-10) = 0, -5 % (-10) = -5 |
480 | // 5 / (-10) = 0, 5 % (-10) = 5 |
481 | ToDuration(value: result, negative: negative1, duration: &d1); |
482 | return d1; |
483 | } |
484 | |
485 | int64_t operator/(const Duration& d1, const Duration& d2) { |
486 | bool negative1, negative2; |
487 | uint128 value1, value2; |
488 | ToUint128(value: d1, result: &value1, negative: &negative1); |
489 | ToUint128(value: d2, result: &value2, negative: &negative2); |
490 | int64_t result = Uint128Low64(v: value1 / value2); |
491 | if (negative1 != negative2) { |
492 | result = -result; |
493 | } |
494 | return result; |
495 | } |
496 | |
497 | Timestamp& operator+=(Timestamp& t, const Duration& d) { // NOLINT |
498 | t = CreateNormalized<Timestamp>(seconds: t.seconds() + d.seconds(), |
499 | nanos: t.nanos() + d.nanos()); |
500 | return t; |
501 | } |
502 | |
503 | Timestamp& operator-=(Timestamp& t, const Duration& d) { // NOLINT |
504 | t = CreateNormalized<Timestamp>(seconds: t.seconds() - d.seconds(), |
505 | nanos: t.nanos() - d.nanos()); |
506 | return t; |
507 | } |
508 | |
509 | Duration operator-(const Timestamp& t1, const Timestamp& t2) { |
510 | return CreateNormalized<Duration>(seconds: t1.seconds() - t2.seconds(), |
511 | nanos: t1.nanos() - t2.nanos()); |
512 | } |
513 | } // namespace protobuf |
514 | } // namespace google |
515 | |