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
45namespace google {
46namespace protobuf {
47namespace util {
48
49using google::protobuf::Duration;
50using google::protobuf::Timestamp;
51
52namespace {
53static const int kNanosPerSecond = 1000000000;
54static const int kMicrosPerSecond = 1000000;
55static const int kMillisPerSecond = 1000;
56static const int kNanosPerMillisecond = 1000000;
57static const int kNanosPerMicrosecond = 1000;
58static const int kSecondsPerMinute = 60; // Note that we ignore leap seconds.
59static const int kSecondsPerHour = 3600;
60
61template <typename T>
62T CreateNormalized(int64_t seconds, int64_t nanos);
63
64template <>
65Timestamp 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
84template <>
85Duration 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.
109std::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
119std::string FormatTime(int64_t seconds, int32_t nanos) {
120 return ::google::protobuf::internal::FormatTime(seconds, nanos);
121}
122
123bool ParseTime(const std::string& value, int64_t* seconds, int32_t* nanos) {
124 return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
125}
126
127void CurrentTime(int64_t* seconds, int32_t* nanos) {
128 return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
129}
130
131// Truncates the remainder part after division.
132int64_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
151const int64_t TimeUtil::kTimestampMinSeconds;
152const int64_t TimeUtil::kTimestampMaxSeconds;
153const int64_t TimeUtil::kDurationMaxSeconds;
154const int64_t TimeUtil::kDurationMinSeconds;
155#endif // !_MSC_VER
156
157std::string TimeUtil::ToString(const Timestamp& timestamp) {
158 return FormatTime(seconds: timestamp.seconds(), nanos: timestamp.nanos());
159}
160
161bool 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
171Timestamp TimeUtil::GetCurrentTime() {
172 int64_t seconds;
173 int32_t nanos;
174 CurrentTime(seconds: &seconds, nanos: &nanos);
175 return CreateNormalized<Timestamp>(seconds, nanos);
176}
177
178Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
179
180std::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
197static 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
205bool 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
242Duration TimeUtil::NanosecondsToDuration(int64_t nanos) {
243 return CreateNormalized<Duration>(seconds: nanos / kNanosPerSecond,
244 nanos: nanos % kNanosPerSecond);
245}
246
247Duration TimeUtil::MicrosecondsToDuration(int64_t micros) {
248 return CreateNormalized<Duration>(
249 seconds: micros / kMicrosPerSecond,
250 nanos: (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
251}
252
253Duration TimeUtil::MillisecondsToDuration(int64_t millis) {
254 return CreateNormalized<Duration>(
255 seconds: millis / kMillisPerSecond,
256 nanos: (millis % kMillisPerSecond) * kNanosPerMillisecond);
257}
258
259Duration TimeUtil::SecondsToDuration(int64_t seconds) {
260 return CreateNormalized<Duration>(seconds, nanos: 0);
261}
262
263Duration TimeUtil::MinutesToDuration(int64_t minutes) {
264 return CreateNormalized<Duration>(seconds: minutes * kSecondsPerMinute, nanos: 0);
265}
266
267Duration TimeUtil::HoursToDuration(int64_t hours) {
268 return CreateNormalized<Duration>(seconds: hours * kSecondsPerHour, nanos: 0);
269}
270
271int64_t TimeUtil::DurationToNanoseconds(const Duration& duration) {
272 return duration.seconds() * kNanosPerSecond + duration.nanos();
273}
274
275int64_t TimeUtil::DurationToMicroseconds(const Duration& duration) {
276 return duration.seconds() * kMicrosPerSecond +
277 RoundTowardZero(value: duration.nanos(), divider: kNanosPerMicrosecond);
278}
279
280int64_t TimeUtil::DurationToMilliseconds(const Duration& duration) {
281 return duration.seconds() * kMillisPerSecond +
282 RoundTowardZero(value: duration.nanos(), divider: kNanosPerMillisecond);
283}
284
285int64_t TimeUtil::DurationToSeconds(const Duration& duration) {
286 return duration.seconds();
287}
288
289int64_t TimeUtil::DurationToMinutes(const Duration& duration) {
290 return RoundTowardZero(value: duration.seconds(), divider: kSecondsPerMinute);
291}
292
293int64_t TimeUtil::DurationToHours(const Duration& duration) {
294 return RoundTowardZero(value: duration.seconds(), divider: kSecondsPerHour);
295}
296
297Timestamp TimeUtil::NanosecondsToTimestamp(int64_t nanos) {
298 return CreateNormalized<Timestamp>(seconds: nanos / kNanosPerSecond,
299 nanos: nanos % kNanosPerSecond);
300}
301
302Timestamp TimeUtil::MicrosecondsToTimestamp(int64_t micros) {
303 return CreateNormalized<Timestamp>(
304 seconds: micros / kMicrosPerSecond,
305 nanos: micros % kMicrosPerSecond * kNanosPerMicrosecond);
306}
307
308Timestamp TimeUtil::MillisecondsToTimestamp(int64_t millis) {
309 return CreateNormalized<Timestamp>(
310 seconds: millis / kMillisPerSecond,
311 nanos: millis % kMillisPerSecond * kNanosPerMillisecond);
312}
313
314Timestamp TimeUtil::SecondsToTimestamp(int64_t seconds) {
315 return CreateNormalized<Timestamp>(seconds, nanos: 0);
316}
317
318int64_t TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
319 return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
320}
321
322int64_t TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
323 return timestamp.seconds() * kMicrosPerSecond +
324 RoundTowardZero(value: timestamp.nanos(), divider: kNanosPerMicrosecond);
325}
326
327int64_t TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
328 return timestamp.seconds() * kMillisPerSecond +
329 RoundTowardZero(value: timestamp.nanos(), divider: kNanosPerMillisecond);
330}
331
332int64_t TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
333 return timestamp.seconds();
334}
335
336Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
337 return CreateNormalized<Timestamp>(seconds: static_cast<int64_t>(value), nanos: 0);
338}
339
340time_t TimeUtil::TimestampToTimeT(const Timestamp& value) {
341 return static_cast<time_t>(value.seconds());
342}
343
344Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) {
345 return CreateNormalized<Timestamp>(seconds: value.tv_sec,
346 nanos: value.tv_usec * kNanosPerMicrosecond);
347}
348
349timeval 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
356Duration TimeUtil::TimevalToDuration(const timeval& value) {
357 return CreateNormalized<Duration>(seconds: value.tv_sec,
358 nanos: value.tv_usec * kNanosPerMicrosecond);
359}
360
361timeval 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
377namespace google {
378namespace protobuf {
379namespace {
380using ::PROTOBUF_NAMESPACE_ID::util::CreateNormalized;
381using ::PROTOBUF_NAMESPACE_ID::util::kNanosPerSecond;
382
383// Convert a Duration to uint128.
384void 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
396void 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
410Duration& 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
416Duration& 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
422Duration& 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
436Duration& 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
451Duration& 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
465Duration& operator/=(Duration& d, double r) { // NOLINT
466 return d *= 1.0 / r;
467}
468
469Duration& 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
485int64_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
497Timestamp& 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
503Timestamp& 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
509Duration 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