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 <>
CreateNormalized(int64_t seconds,int64_t nanos)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 <>
CreateNormalized(int64_t seconds,int64_t nanos)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.
FormatNanos(int32_t nanos)109 std::string FormatNanos(int32_t nanos) {
110 if (nanos % kNanosPerMillisecond == 0) {
111 return StringPrintf("%03d", nanos / kNanosPerMillisecond);
112 } else if (nanos % kNanosPerMicrosecond == 0) {
113 return StringPrintf("%06d", nanos / kNanosPerMicrosecond);
114 } else {
115 return StringPrintf("%09d", nanos);
116 }
117 }
118
FormatTime(int64 seconds,int32 nanos)119 std::string FormatTime(int64 seconds, int32 nanos) {
120 return ::google::protobuf::internal::FormatTime(seconds, nanos);
121 }
122
ParseTime(const std::string & value,int64 * seconds,int32 * nanos)123 bool ParseTime(const std::string& value, int64* seconds, int32* nanos) {
124 return ::google::protobuf::internal::ParseTime(value, seconds, nanos);
125 }
126
CurrentTime(int64 * seconds,int32 * nanos)127 void CurrentTime(int64* seconds, int32* nanos) {
128 return ::google::protobuf::internal::GetCurrentTime(seconds, nanos);
129 }
130
131 // Truncates the remainder part after division.
RoundTowardZero(int64_t value,int64_t divider)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
ToString(const Timestamp & timestamp)157 std::string TimeUtil::ToString(const Timestamp& timestamp) {
158 return FormatTime(timestamp.seconds(), timestamp.nanos());
159 }
160
FromString(const std::string & value,Timestamp * timestamp)161 bool TimeUtil::FromString(const std::string& value, Timestamp* timestamp) {
162 int64_t seconds;
163 int32_t nanos;
164 if (!ParseTime(value, &seconds, &nanos)) {
165 return false;
166 }
167 *timestamp = CreateNormalized<Timestamp>(seconds, nanos);
168 return true;
169 }
170
GetCurrentTime()171 Timestamp TimeUtil::GetCurrentTime() {
172 int64_t seconds;
173 int32_t nanos;
174 CurrentTime(&seconds, &nanos);
175 return CreateNormalized<Timestamp>(seconds, nanos);
176 }
177
GetEpoch()178 Timestamp TimeUtil::GetEpoch() { return Timestamp(); }
179
ToString(const Duration & duration)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(seconds);
190 if (nanos != 0) {
191 result += "." + FormatNanos(nanos);
192 }
193 result += "s";
194 return result;
195 }
196
Pow(int64_t x,int y)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
FromString(const std::string & value,Duration * duration)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 int 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('.');
215 if (pos == std::string::npos) {
216 seconds_part = value.substr(sign_length, value.length() - 1 - sign_length);
217 nanos_part = "0";
218 } else {
219 seconds_part = value.substr(sign_length, pos - sign_length);
220 nanos_part = value.substr(pos + 1, value.length() - pos - 2);
221 }
222 char* end;
223 int64_t seconds = strto64(seconds_part.c_str(), &end, 10);
224 if (end != seconds_part.c_str() + seconds_part.length()) {
225 return false;
226 }
227 int64_t nanos = strto64(nanos_part.c_str(), &end, 10);
228 if (end != nanos_part.c_str() + nanos_part.length()) {
229 return false;
230 }
231 nanos = nanos * Pow(10, 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
NanosecondsToDuration(int64_t nanos)242 Duration TimeUtil::NanosecondsToDuration(int64_t nanos) {
243 return CreateNormalized<Duration>(nanos / kNanosPerSecond,
244 nanos % kNanosPerSecond);
245 }
246
MicrosecondsToDuration(int64_t micros)247 Duration TimeUtil::MicrosecondsToDuration(int64_t micros) {
248 return CreateNormalized<Duration>(
249 micros / kMicrosPerSecond,
250 (micros % kMicrosPerSecond) * kNanosPerMicrosecond);
251 }
252
MillisecondsToDuration(int64_t millis)253 Duration TimeUtil::MillisecondsToDuration(int64_t millis) {
254 return CreateNormalized<Duration>(
255 millis / kMillisPerSecond,
256 (millis % kMillisPerSecond) * kNanosPerMillisecond);
257 }
258
SecondsToDuration(int64_t seconds)259 Duration TimeUtil::SecondsToDuration(int64_t seconds) {
260 return CreateNormalized<Duration>(seconds, 0);
261 }
262
MinutesToDuration(int64_t minutes)263 Duration TimeUtil::MinutesToDuration(int64_t minutes) {
264 return CreateNormalized<Duration>(minutes * kSecondsPerMinute, 0);
265 }
266
HoursToDuration(int64_t hours)267 Duration TimeUtil::HoursToDuration(int64_t hours) {
268 return CreateNormalized<Duration>(hours * kSecondsPerHour, 0);
269 }
270
DurationToNanoseconds(const Duration & duration)271 int64_t TimeUtil::DurationToNanoseconds(const Duration& duration) {
272 return duration.seconds() * kNanosPerSecond + duration.nanos();
273 }
274
DurationToMicroseconds(const Duration & duration)275 int64_t TimeUtil::DurationToMicroseconds(const Duration& duration) {
276 return duration.seconds() * kMicrosPerSecond +
277 RoundTowardZero(duration.nanos(), kNanosPerMicrosecond);
278 }
279
DurationToMilliseconds(const Duration & duration)280 int64_t TimeUtil::DurationToMilliseconds(const Duration& duration) {
281 return duration.seconds() * kMillisPerSecond +
282 RoundTowardZero(duration.nanos(), kNanosPerMillisecond);
283 }
284
DurationToSeconds(const Duration & duration)285 int64_t TimeUtil::DurationToSeconds(const Duration& duration) {
286 return duration.seconds();
287 }
288
DurationToMinutes(const Duration & duration)289 int64_t TimeUtil::DurationToMinutes(const Duration& duration) {
290 return RoundTowardZero(duration.seconds(), kSecondsPerMinute);
291 }
292
DurationToHours(const Duration & duration)293 int64_t TimeUtil::DurationToHours(const Duration& duration) {
294 return RoundTowardZero(duration.seconds(), kSecondsPerHour);
295 }
296
NanosecondsToTimestamp(int64_t nanos)297 Timestamp TimeUtil::NanosecondsToTimestamp(int64_t nanos) {
298 return CreateNormalized<Timestamp>(nanos / kNanosPerSecond,
299 nanos % kNanosPerSecond);
300 }
301
MicrosecondsToTimestamp(int64_t micros)302 Timestamp TimeUtil::MicrosecondsToTimestamp(int64_t micros) {
303 return CreateNormalized<Timestamp>(
304 micros / kMicrosPerSecond,
305 micros % kMicrosPerSecond * kNanosPerMicrosecond);
306 }
307
MillisecondsToTimestamp(int64_t millis)308 Timestamp TimeUtil::MillisecondsToTimestamp(int64_t millis) {
309 return CreateNormalized<Timestamp>(
310 millis / kMillisPerSecond,
311 millis % kMillisPerSecond * kNanosPerMillisecond);
312 }
313
SecondsToTimestamp(int64_t seconds)314 Timestamp TimeUtil::SecondsToTimestamp(int64_t seconds) {
315 return CreateNormalized<Timestamp>(seconds, 0);
316 }
317
TimestampToNanoseconds(const Timestamp & timestamp)318 int64_t TimeUtil::TimestampToNanoseconds(const Timestamp& timestamp) {
319 return timestamp.seconds() * kNanosPerSecond + timestamp.nanos();
320 }
321
TimestampToMicroseconds(const Timestamp & timestamp)322 int64_t TimeUtil::TimestampToMicroseconds(const Timestamp& timestamp) {
323 return timestamp.seconds() * kMicrosPerSecond +
324 RoundTowardZero(timestamp.nanos(), kNanosPerMicrosecond);
325 }
326
TimestampToMilliseconds(const Timestamp & timestamp)327 int64_t TimeUtil::TimestampToMilliseconds(const Timestamp& timestamp) {
328 return timestamp.seconds() * kMillisPerSecond +
329 RoundTowardZero(timestamp.nanos(), kNanosPerMillisecond);
330 }
331
TimestampToSeconds(const Timestamp & timestamp)332 int64_t TimeUtil::TimestampToSeconds(const Timestamp& timestamp) {
333 return timestamp.seconds();
334 }
335
TimeTToTimestamp(time_t value)336 Timestamp TimeUtil::TimeTToTimestamp(time_t value) {
337 return CreateNormalized<Timestamp>(static_cast<int64_t>(value), 0);
338 }
339
TimestampToTimeT(const Timestamp & value)340 time_t TimeUtil::TimestampToTimeT(const Timestamp& value) {
341 return static_cast<time_t>(value.seconds());
342 }
343
TimevalToTimestamp(const timeval & value)344 Timestamp TimeUtil::TimevalToTimestamp(const timeval& value) {
345 return CreateNormalized<Timestamp>(value.tv_sec,
346 value.tv_usec * kNanosPerMicrosecond);
347 }
348
TimestampToTimeval(const Timestamp & value)349 timeval TimeUtil::TimestampToTimeval(const Timestamp& value) {
350 timeval result;
351 result.tv_sec = value.seconds();
352 result.tv_usec = RoundTowardZero(value.nanos(), kNanosPerMicrosecond);
353 return result;
354 }
355
TimevalToDuration(const timeval & value)356 Duration TimeUtil::TimevalToDuration(const timeval& value) {
357 return CreateNormalized<Duration>(value.tv_sec,
358 value.tv_usec * kNanosPerMicrosecond);
359 }
360
DurationToTimeval(const Duration & value)361 timeval TimeUtil::DurationToTimeval(const Duration& value) {
362 timeval result;
363 result.tv_sec = value.seconds();
364 result.tv_usec = RoundTowardZero(value.nanos(), 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.
ToUint128(const Duration & value,uint128 * result,bool * negative)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
ToDuration(const uint128 & value,bool negative,Duration * duration)396 void ToDuration(const uint128& value, bool negative, Duration* duration) {
397 int64_t seconds =
398 static_cast<int64_t>(Uint128Low64(value / kNanosPerSecond));
399 int32_t nanos =
400 static_cast<int32_t>(Uint128Low64(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
operator +=(Duration & d1,const Duration & d2)410 Duration& operator+=(Duration& d1, const Duration& d2) {
411 d1 = CreateNormalized<Duration>(d1.seconds() + d2.seconds(),
412 d1.nanos() + d2.nanos());
413 return d1;
414 }
415
operator -=(Duration & d1,const Duration & d2)416 Duration& operator-=(Duration& d1, const Duration& d2) { // NOLINT
417 d1 = CreateNormalized<Duration>(d1.seconds() - d2.seconds(),
418 d1.nanos() - d2.nanos());
419 return d1;
420 }
421
operator *=(Duration & d,int64_t r)422 Duration& operator*=(Duration& d, int64_t r) { // NOLINT
423 bool negative;
424 uint128 value;
425 ToUint128(d, &value, &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, &d);
433 return d;
434 }
435
operator *=(Duration & d,double r)436 Duration& operator*=(Duration& d, double r) { // NOLINT
437 double result = (d.seconds() * 1.0 + 1.0 * d.nanos() / kNanosPerSecond) * r;
438 int64_t seconds = static_cast<int64_t>(result);
439 int32_t nanos = static_cast<int32_t>((result - seconds) * kNanosPerSecond);
440 // Note that we normalize here not just because nanos can have a different
441 // sign from seconds but also that nanos can be any arbitrary value when
442 // overflow happens (i.e., the result is a much larger value than what
443 // int64 can represent).
444 d = CreateNormalized<Duration>(seconds, nanos);
445 return d;
446 }
447
operator /=(Duration & d,int64_t r)448 Duration& operator/=(Duration& d, int64_t r) { // NOLINT
449 bool negative;
450 uint128 value;
451 ToUint128(d, &value, &negative);
452 if (r > 0) {
453 value /= static_cast<uint64_t>(r);
454 } else {
455 negative = !negative;
456 value /= static_cast<uint64_t>(-r);
457 }
458 ToDuration(value, negative, &d);
459 return d;
460 }
461
operator /=(Duration & d,double r)462 Duration& operator/=(Duration& d, double r) { // NOLINT
463 return d *= 1.0 / r;
464 }
465
operator %=(Duration & d1,const Duration & d2)466 Duration& operator%=(Duration& d1, const Duration& d2) { // NOLINT
467 bool negative1, negative2;
468 uint128 value1, value2;
469 ToUint128(d1, &value1, &negative1);
470 ToUint128(d2, &value2, &negative2);
471 uint128 result = value1 % value2;
472 // When negative values are involved in division, we round the division
473 // result towards zero. With this semantics, sign of the remainder is the
474 // same as the dividend. For example:
475 // -5 / 10 = 0, -5 % 10 = -5
476 // -5 / (-10) = 0, -5 % (-10) = -5
477 // 5 / (-10) = 0, 5 % (-10) = 5
478 ToDuration(result, negative1, &d1);
479 return d1;
480 }
481
operator /(const Duration & d1,const Duration & d2)482 int64_t operator/(const Duration& d1, const Duration& d2) {
483 bool negative1, negative2;
484 uint128 value1, value2;
485 ToUint128(d1, &value1, &negative1);
486 ToUint128(d2, &value2, &negative2);
487 int64_t result = Uint128Low64(value1 / value2);
488 if (negative1 != negative2) {
489 result = -result;
490 }
491 return result;
492 }
493
operator +=(Timestamp & t,const Duration & d)494 Timestamp& operator+=(Timestamp& t, const Duration& d) { // NOLINT
495 t = CreateNormalized<Timestamp>(t.seconds() + d.seconds(),
496 t.nanos() + d.nanos());
497 return t;
498 }
499
operator -=(Timestamp & t,const Duration & d)500 Timestamp& operator-=(Timestamp& t, const Duration& d) { // NOLINT
501 t = CreateNormalized<Timestamp>(t.seconds() - d.seconds(),
502 t.nanos() - d.nanos());
503 return t;
504 }
505
operator -(const Timestamp & t1,const Timestamp & t2)506 Duration operator-(const Timestamp& t1, const Timestamp& t2) {
507 return CreateNormalized<Duration>(t1.seconds() - t2.seconds(),
508 t1.nanos() - t2.nanos());
509 }
510 } // namespace protobuf
511 } // namespace google
512