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