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