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