• 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/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