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