31 package com.google.protobuf.util;
33 import static com.
google.common.base.Preconditions.checkArgument;
34 import static com.
google.common.math.IntMath.checkedAdd;
35 import static com.
google.common.math.IntMath.checkedSubtract;
36 import static com.
google.common.math.LongMath.checkedAdd;
37 import static com.
google.common.math.LongMath.checkedMultiply;
38 import static com.
google.common.math.LongMath.checkedSubtract;
45 import com.
google.errorprone.annotations.CanIgnoreReturnValue;
47 import java.text.ParseException;
48 import java.util.Comparator;
55 static final long DURATION_SECONDS_MIN = -315576000000L;
56 static final long DURATION_SECONDS_MAX = 315576000000L;
64 Duration.newBuilder().setSeconds(DURATION_SECONDS_MIN).setNanos(-999999999).build();
68 Duration.newBuilder().setSeconds(DURATION_SECONDS_MAX).setNanos(999999999).build();
76 new Comparator<Duration>() {
81 int secDiff = Long.compare(d1.getSeconds(), d2.getSeconds());
82 return (secDiff != 0) ? secDiff : Integer.compare(d1.getNanos(), d2.getNanos());
115 return isValid(duration.getSeconds(), duration.getNanos());
127 @SuppressWarnings(
"GoodTime")
128 public static
boolean isValid(
long seconds,
int nanos) {
129 if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
132 if (nanos < -999999999L || nanos >= NANOS_PER_SECOND) {
135 if (seconds < 0 || nanos < 0) {
136 if (seconds > 0 || nanos > 0) {
146 return (duration.getSeconds() == 0) ? duration.getNanos() < 0 : duration.getSeconds() < 0;
155 @CanIgnoreReturnValue
158 checkArgument(!
isNegative(duration),
"duration (%s) must not be negative",
toString(duration));
168 @CanIgnoreReturnValue
173 "duration (%s) must be positive",
179 @CanIgnoreReturnValue
181 long seconds = duration.getSeconds();
182 int nanos = duration.getNanos();
183 if (!
isValid(seconds, nanos)) {
184 throw new IllegalArgumentException(
186 "Duration is not valid. See proto definition for valid values. "
187 +
"Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]. "
188 +
"Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
189 +
"Nanos must have the same sign as seconds",
217 long seconds = duration.getSeconds();
218 int nanos = duration.getNanos();
220 StringBuilder result =
new StringBuilder();
221 if (seconds < 0 || nanos < 0) {
226 result.append(seconds);
232 return result.toString();
244 throw new ParseException(
"Invalid duration string: " +
value, 0);
246 boolean negative =
false;
247 if (
value.charAt(0) ==
'-') {
251 String secondValue =
value.substring(0,
value.length() - 1);
252 String nanoValue =
"";
253 int pointPosition = secondValue.indexOf(
'.');
254 if (pointPosition != -1) {
255 nanoValue = secondValue.substring(pointPosition + 1);
256 secondValue = secondValue.substring(0, pointPosition);
258 long seconds = Long.parseLong(secondValue);
259 int nanos = nanoValue.isEmpty() ? 0 :
Timestamps.parseNanos(nanoValue);
261 throw new ParseException(
"Invalid duration string: " +
value, 0);
268 return normalizedDuration(seconds, nanos);
269 }
catch (IllegalArgumentException e) {
270 throw new ParseException(
"Duration value is out of range.", 0);
277 @SuppressWarnings(
"GoodTime")
286 @SuppressWarnings(
"GoodTime")
295 @SuppressWarnings(
"GoodTime")
304 @SuppressWarnings(
"GoodTime")
306 return normalizedDuration(seconds, 0);
310 @SuppressWarnings(
"GoodTime")
312 return normalizedDuration(
313 milliseconds / MILLIS_PER_SECOND,
314 (
int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
318 @SuppressWarnings(
"GoodTime")
320 return normalizedDuration(
321 microseconds / MICROS_PER_SECOND,
322 (
int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
326 @SuppressWarnings(
"GoodTime")
328 return normalizedDuration(
329 nanoseconds / NANOS_PER_SECOND, (
int) (nanoseconds % NANOS_PER_SECOND));
338 @SuppressWarnings(
"GoodTime")
347 @SuppressWarnings(
"GoodTime")
356 @SuppressWarnings(
"GoodTime")
365 @SuppressWarnings(
"GoodTime")
380 "DurationSecondsToDouble",
385 return duration.getSeconds() + duration.getNanos() / 1e9;
392 @SuppressWarnings(
"GoodTime")
396 checkedMultiply(duration.getSeconds(), MILLIS_PER_SECOND),
397 duration.getNanos() / NANOS_PER_MILLISECOND);
404 @SuppressWarnings(
"GoodTime")
408 checkedMultiply(duration.getSeconds(), MICROS_PER_SECOND),
409 duration.getNanos() / NANOS_PER_MICROSECOND);
413 @SuppressWarnings(
"GoodTime")
417 checkedMultiply(duration.getSeconds(), NANOS_PER_SECOND), duration.getNanos());
426 return normalizedDuration(
427 checkedAdd(d1.getSeconds(), d2.getSeconds()), checkedAdd(d1.getNanos(), d2.getNanos()));
434 return normalizedDuration(
435 checkedSubtract(d1.getSeconds(), d2.getSeconds()),
436 checkedSubtract(d1.getNanos(), d2.getNanos()));
439 static Duration normalizedDuration(
long seconds,
int nanos) {
440 if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
441 seconds = checkedAdd(seconds, nanos / NANOS_PER_SECOND);
442 nanos %= NANOS_PER_SECOND;
444 if (seconds > 0 && nanos < 0) {
445 nanos += NANOS_PER_SECOND;
448 if (seconds < 0 && nanos > 0) {
449 nanos -= NANOS_PER_SECOND;
452 Duration duration =
Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();