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