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