77 import java.math.RoundingMode; |
81 import java.math.RoundingMode; |
78 import java.time.format.DateTimeParseException; |
82 import java.time.format.DateTimeParseException; |
79 import java.time.temporal.ChronoField; |
83 import java.time.temporal.ChronoField; |
80 import java.time.temporal.ChronoUnit; |
84 import java.time.temporal.ChronoUnit; |
81 import java.time.temporal.Temporal; |
85 import java.time.temporal.Temporal; |
82 import java.time.temporal.TemporalAccessor; |
86 import java.time.temporal.TemporalAmount; |
83 import java.time.temporal.TemporalAdder; |
|
84 import java.time.temporal.TemporalSubtractor; |
|
85 import java.time.temporal.TemporalUnit; |
87 import java.time.temporal.TemporalUnit; |
|
88 import java.util.Arrays; |
|
89 import java.util.Collections; |
|
90 import java.util.List; |
86 import java.util.Objects; |
91 import java.util.Objects; |
|
92 import java.util.regex.Matcher; |
|
93 import java.util.regex.Pattern; |
87 |
94 |
88 /** |
95 /** |
89 * A duration between two instants on the time-line. |
96 * A time-based amount of time, such as '34.5 seconds'. |
90 * <p> |
97 * <p> |
91 * This class models a duration of time and is not tied to any instant. |
98 * This class models a quantity or amount of time in terms of seconds and nanoseconds. |
92 * The model is of a directed duration, meaning that the duration may be negative. |
99 * It can be accessed using other duration-based units, such as minutes and hours. |
|
100 * In addition, the {@link ChronoUnit#DAYS DAYS} unit can be used and is treated as |
|
101 * exactly equal to 24 hours, thus ignoring daylight savings effects. |
|
102 * See {@link Period} for the date-based equivalent to this class. |
93 * <p> |
103 * <p> |
94 * A physical duration could be of infinite length. |
104 * A physical duration could be of infinite length. |
95 * For practicality, the duration is stored with constraints similar to {@link Instant}. |
105 * For practicality, the duration is stored with constraints similar to {@link Instant}. |
96 * The duration uses nanosecond resolution with a maximum value of the seconds that can |
106 * The duration uses nanosecond resolution with a maximum value of the seconds that can |
97 * be held in a {@code long}. This is greater than the current estimated age of the universe. |
107 * be held in a {@code long}. This is greater than the current estimated age of the universe. |
98 * <p> |
108 * <p> |
99 * The range of a duration requires the storage of a number larger than a {@code long}. |
109 * The range of a duration requires the storage of a number larger than a {@code long}. |
100 * To achieve this, the class stores a {@code long} representing seconds and an {@code int} |
110 * To achieve this, the class stores a {@code long} representing seconds and an {@code int} |
101 * representing nanosecond-of-second, which will always be between 0 and 999,999,999. |
111 * representing nanosecond-of-second, which will always be between 0 and 999,999,999. |
|
112 * The model is of a directed duration, meaning that the duration may be negative. |
102 * <p> |
113 * <p> |
103 * The duration is measured in "seconds", but these are not necessarily identical to |
114 * The duration is measured in "seconds", but these are not necessarily identical to |
104 * the scientific "SI second" definition based on atomic clocks. |
115 * the scientific "SI second" definition based on atomic clocks. |
105 * This difference only impacts durations measured near a leap-second and should not affect |
116 * This difference only impacts durations measured near a leap-second and should not affect |
106 * most applications. |
117 * most applications. |
141 */ |
155 */ |
142 private final int nanos; |
156 private final int nanos; |
143 |
157 |
144 //----------------------------------------------------------------------- |
158 //----------------------------------------------------------------------- |
145 /** |
159 /** |
146 * Obtains an instance of {@code Duration} from a number of seconds. |
160 * Obtains a {@code Duration} representing a number of standard 24 hour days. |
|
161 * <p> |
|
162 * The seconds are calculated based on the standard definition of a day, |
|
163 * where each day is 86400 seconds which implies a 24 hour day. |
|
164 * The nanosecond in second field is set to zero. |
|
165 * |
|
166 * @param days the number of days, positive or negative |
|
167 * @return a {@code Duration}, not null |
|
168 * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} |
|
169 */ |
|
170 public static Duration ofDays(long days) { |
|
171 return create(Math.multiplyExact(days, SECONDS_PER_DAY), 0); |
|
172 } |
|
173 |
|
174 /** |
|
175 * Obtains a {@code Duration} representing a number of standard hours. |
|
176 * <p> |
|
177 * The seconds are calculated based on the standard definition of an hour, |
|
178 * where each hour is 3600 seconds. |
|
179 * The nanosecond in second field is set to zero. |
|
180 * |
|
181 * @param hours the number of hours, positive or negative |
|
182 * @return a {@code Duration}, not null |
|
183 * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} |
|
184 */ |
|
185 public static Duration ofHours(long hours) { |
|
186 return create(Math.multiplyExact(hours, SECONDS_PER_HOUR), 0); |
|
187 } |
|
188 |
|
189 /** |
|
190 * Obtains a {@code Duration} representing a number of standard minutes. |
|
191 * <p> |
|
192 * The seconds are calculated based on the standard definition of a minute, |
|
193 * where each minute is 60 seconds. |
|
194 * The nanosecond in second field is set to zero. |
|
195 * |
|
196 * @param minutes the number of minutes, positive or negative |
|
197 * @return a {@code Duration}, not null |
|
198 * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} |
|
199 */ |
|
200 public static Duration ofMinutes(long minutes) { |
|
201 return create(Math.multiplyExact(minutes, SECONDS_PER_MINUTE), 0); |
|
202 } |
|
203 |
|
204 //----------------------------------------------------------------------- |
|
205 /** |
|
206 * Obtains a {@code Duration} representing a number of seconds. |
147 * <p> |
207 * <p> |
148 * The nanosecond in second field is set to zero. |
208 * The nanosecond in second field is set to zero. |
149 * |
209 * |
150 * @param seconds the number of seconds, positive or negative |
210 * @param seconds the number of seconds, positive or negative |
151 * @return a {@code Duration}, not null |
211 * @return a {@code Duration}, not null |
217 return create(secs, nos); |
277 return create(secs, nos); |
218 } |
278 } |
219 |
279 |
220 //----------------------------------------------------------------------- |
280 //----------------------------------------------------------------------- |
221 /** |
281 /** |
222 * Obtains an instance of {@code Duration} from a number of standard length minutes. |
282 * Obtains a {@code Duration} representing an amount in the specified unit. |
223 * <p> |
|
224 * The seconds are calculated based on the standard definition of a minute, |
|
225 * where each minute is 60 seconds. |
|
226 * The nanosecond in second field is set to zero. |
|
227 * |
|
228 * @param minutes the number of minutes, positive or negative |
|
229 * @return a {@code Duration}, not null |
|
230 * @throws ArithmeticException if the input minutes exceeds the capacity of {@code Duration} |
|
231 */ |
|
232 public static Duration ofMinutes(long minutes) { |
|
233 return create(Math.multiplyExact(minutes, 60), 0); |
|
234 } |
|
235 |
|
236 /** |
|
237 * Obtains an instance of {@code Duration} from a number of standard length hours. |
|
238 * <p> |
|
239 * The seconds are calculated based on the standard definition of an hour, |
|
240 * where each hour is 3600 seconds. |
|
241 * The nanosecond in second field is set to zero. |
|
242 * |
|
243 * @param hours the number of hours, positive or negative |
|
244 * @return a {@code Duration}, not null |
|
245 * @throws ArithmeticException if the input hours exceeds the capacity of {@code Duration} |
|
246 */ |
|
247 public static Duration ofHours(long hours) { |
|
248 return create(Math.multiplyExact(hours, 3600), 0); |
|
249 } |
|
250 |
|
251 /** |
|
252 * Obtains an instance of {@code Duration} from a number of standard 24 hour days. |
|
253 * <p> |
|
254 * The seconds are calculated based on the standard definition of a day, |
|
255 * where each day is 86400 seconds which implies a 24 hour day. |
|
256 * The nanosecond in second field is set to zero. |
|
257 * |
|
258 * @param days the number of days, positive or negative |
|
259 * @return a {@code Duration}, not null |
|
260 * @throws ArithmeticException if the input days exceeds the capacity of {@code Duration} |
|
261 */ |
|
262 public static Duration ofDays(long days) { |
|
263 return create(Math.multiplyExact(days, 86400), 0); |
|
264 } |
|
265 |
|
266 //----------------------------------------------------------------------- |
|
267 /** |
|
268 * Obtains an instance of {@code Duration} from a duration in the specified unit. |
|
269 * <p> |
283 * <p> |
270 * The parameters represent the two parts of a phrase like '6 Hours'. For example: |
284 * The parameters represent the two parts of a phrase like '6 Hours'. For example: |
271 * <pre> |
285 * <pre> |
272 * Duration.of(3, SECONDS); |
286 * Duration.of(3, SECONDS); |
273 * Duration.of(465, HOURS); |
287 * Duration.of(465, HOURS); |
286 return ZERO.plus(amount, unit); |
300 return ZERO.plus(amount, unit); |
287 } |
301 } |
288 |
302 |
289 //----------------------------------------------------------------------- |
303 //----------------------------------------------------------------------- |
290 /** |
304 /** |
291 * Obtains an instance of {@code Duration} representing the duration between two instants. |
305 * Obtains a {@code Duration} representing the duration between two instants. |
292 * <p> |
306 * <p> |
293 * A {@code Duration} represents a directed distance between two points on the time-line. |
307 * This calculates the duration between two temporal objects of the same type. |
294 * As such, this method will return a negative duration if the end is before the start. |
308 * The difference in seconds is calculated using |
295 * To guarantee to obtain a positive duration call {@link #abs()} on the result of this factory. |
309 * {@link Temporal#periodUntil(Temporal, TemporalUnit)}. |
|
310 * The difference in nanoseconds is calculated using by querying the |
|
311 * {@link ChronoField#NANO_OF_SECOND NANO_OF_SECOND} field. |
|
312 * <p> |
|
313 * The result of this method can be a negative period if the end is before the start. |
|
314 * To guarantee to obtain a positive duration call {@link #abs()} on the result. |
296 * |
315 * |
297 * @param startInclusive the start instant, inclusive, not null |
316 * @param startInclusive the start instant, inclusive, not null |
298 * @param endExclusive the end instant, exclusive, not null |
317 * @param endExclusive the end instant, exclusive, not null |
299 * @return a {@code Duration}, not null |
318 * @return a {@code Duration}, not null |
300 * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} |
319 * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} |
301 */ |
320 */ |
302 public static Duration between(TemporalAccessor startInclusive, TemporalAccessor endExclusive) { |
321 public static Duration between(Temporal startInclusive, Temporal endExclusive) { |
303 long secs = Math.subtractExact(endExclusive.getLong(INSTANT_SECONDS), startInclusive.getLong(INSTANT_SECONDS)); |
322 long secs = startInclusive.periodUntil(endExclusive, SECONDS); |
304 long nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); |
323 long nanos; |
305 secs = Math.addExact(secs, Math.floorDiv(nanos, NANOS_PER_SECOND)); |
324 try { |
306 nanos = Math.floorMod(nanos, NANOS_PER_SECOND); |
325 nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); |
307 return create(secs, (int) nanos); // safe from overflow |
326 } catch (DateTimeException ex) { |
308 } |
327 nanos = 0; |
309 |
328 } |
310 //----------------------------------------------------------------------- |
329 return ofSeconds(secs, nanos); |
311 /** |
330 } |
312 * Obtains an instance of {@code Duration} by parsing a text string. |
331 |
313 * <p> |
332 //----------------------------------------------------------------------- |
314 * This will parse the string produced by {@link #toString()} which is |
333 /** |
315 * the ISO-8601 format {@code PTnS} where {@code n} is |
334 * Obtains a {@code Duration} from a text string such as {@code PnDTnHnMn.nS}. |
316 * the number of seconds with optional decimal part. |
335 * <p> |
317 * The number must consist of ASCII numerals. |
336 * This will parse a textual representation of a duration, including the |
318 * There must only be a negative sign at the start of the number and it can |
337 * string produced by {@code toString()}. The formats accepted are based |
319 * only be present if the value is less than zero. |
338 * on the ISO-8601 duration format {@code PnDTnHnMn.nS} with days |
320 * There must be at least one digit before any decimal point. |
339 * considered to be exactly 24 hours. |
321 * There must be between 1 and 9 inclusive digits after any decimal point. |
340 * <p> |
322 * The letters (P, T and S) will be accepted in upper or lower case. |
341 * The string starts with an optional sign, denoted by the ASCII negative |
|
342 * or positive symbol. If negative, the whole period is negated. |
|
343 * The ASCII letter "P" is next in upper or lower case. |
|
344 * There are then four sections, each consisting of a number and a suffix. |
|
345 * The sections have suffixes in ASCII of "D", "H", "M" and "S" for |
|
346 * days, hours, minutes and seconds, accepted in upper or lower case. |
|
347 * The suffixes must occur in order. The ASCII letter "T" must occur before |
|
348 * the first occurrence, if any, of an hour, minute or second section. |
|
349 * At least one of the four sections must be present, and if "T" is present |
|
350 * there must be at least one section after the "T". |
|
351 * The number part of each section must consist of one or more ASCII digits. |
|
352 * The number may be prefixed by the ASCII negative or positive symbol. |
|
353 * The number of days, hours and minutes must parse to an {@code long}. |
|
354 * The number of seconds must parse to an {@code long} with optional fraction. |
323 * The decimal point may be either a dot or a comma. |
355 * The decimal point may be either a dot or a comma. |
|
356 * The fractional part may have from zero to 9 digits. |
|
357 * <p> |
|
358 * The leading plus/minus sign, and negative values for other units are |
|
359 * not part of the ISO-8601 standard. |
|
360 * <p> |
|
361 * Examples: |
|
362 * <pre> |
|
363 * "PT20.345S" -> parses as "20.345 seconds" |
|
364 * "PT15M" -> parses as "15 minutes" (where a minute is 60 seconds) |
|
365 * "PT10H" -> parses as "10 hours" (where an hour is 3600 seconds) |
|
366 * "P2D" -> parses as "2 days" (where a day is 24 hours or 86400 seconds) |
|
367 * "P2DT3H4M" -> parses as "2 days, 3 hours and 4 minutes" |
|
368 * "P-6H3M" -> parses as "-6 hours and +3 minutes" |
|
369 * "-P6H3M" -> parses as "-6 hours and -3 minutes" |
|
370 * "-P-6H+3M" -> parses as "+6 hours and -3 minutes" |
|
371 * </pre> |
324 * |
372 * |
325 * @param text the text to parse, not null |
373 * @param text the text to parse, not null |
326 * @return a {@code Duration}, not null |
374 * @return the parsed duration, not null |
327 * @throws DateTimeParseException if the text cannot be parsed to a {@code Duration} |
375 * @throws DateTimeParseException if the text cannot be parsed to a duration |
328 */ |
376 */ |
329 public static Duration parse(final CharSequence text) { |
377 public static Duration parse(CharSequence text) { |
330 Objects.requireNonNull(text, "text"); |
378 Objects.requireNonNull(text, "text"); |
331 int len = text.length(); |
379 Matcher matcher = PATTERN.matcher(text); |
332 if (len < 4 || |
380 if (matcher.matches()) { |
333 (text.charAt(0) != 'P' && text.charAt(0) != 'p') || |
381 // check for letter T but no time sections |
334 (text.charAt(1) != 'T' && text.charAt(1) != 't') || |
382 if ("T".equals(matcher.group(3)) == false) { |
335 (text.charAt(len - 1) != 'S' && text.charAt(len - 1) != 's') || |
383 boolean negate = "-".equals(matcher.group(1)); |
336 (len == 5 && text.charAt(2) == '-' && text.charAt(3) == '0')) { |
384 String dayMatch = matcher.group(2); |
337 throw new DateTimeParseException("Duration could not be parsed: " + text, text, 0); |
385 String hourMatch = matcher.group(4); |
338 } |
386 String minuteMatch = matcher.group(5); |
339 String numberText = text.subSequence(2, len - 1).toString().replace(',', '.'); |
387 String secondMatch = matcher.group(6); |
340 if (numberText.charAt(0) == '+') { |
388 String fractionMatch = matcher.group(7); |
341 throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); |
389 if (dayMatch != null || hourMatch != null || minuteMatch != null || secondMatch != null) { |
342 } |
390 long daysAsSecs = parseNumber(text, dayMatch, SECONDS_PER_DAY, "days"); |
343 int dot = numberText.indexOf('.'); |
391 long hoursAsSecs = parseNumber(text, hourMatch, SECONDS_PER_HOUR, "hours"); |
|
392 long minsAsSecs = parseNumber(text, minuteMatch, SECONDS_PER_MINUTE, "minutes"); |
|
393 long seconds = parseNumber(text, secondMatch, 1, "seconds"); |
|
394 int nanos = parseFraction(text, fractionMatch, seconds < 0 ? -1 : 1); |
|
395 try { |
|
396 return create(negate, daysAsSecs, hoursAsSecs, minsAsSecs, seconds, nanos); |
|
397 } catch (ArithmeticException ex) { |
|
398 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: overflow", text, 0).initCause(ex); |
|
399 } |
|
400 } |
|
401 } |
|
402 } |
|
403 throw new DateTimeParseException("Text cannot be parsed to a Duration", text, 0); |
|
404 } |
|
405 |
|
406 private static long parseNumber(CharSequence text, String parsed, int multiplier, String errorText) { |
|
407 // regex limits to [-+]?[0-9]+ |
|
408 if (parsed == null) { |
|
409 return 0; |
|
410 } |
344 try { |
411 try { |
345 if (dot == -1) { |
412 long val = Long.parseLong(parsed); |
346 // no decimal places |
413 return Math.multiplyExact(val, multiplier); |
347 if (numberText.startsWith("-0")) { |
414 } catch (NumberFormatException | ArithmeticException ex) { |
348 throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); |
415 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: " + errorText, text, 0).initCause(ex); |
349 } |
416 } |
350 return create(Long.parseLong(numberText), 0); |
417 } |
351 } |
418 |
352 // decimal places |
419 private static int parseFraction(CharSequence text, String parsed, int negate) { |
353 boolean negative = false; |
420 // regex limits to [0-9]{0,9} |
354 if (numberText.charAt(0) == '-') { |
421 if (parsed == null || parsed.length() == 0) { |
355 negative = true; |
422 return 0; |
356 } |
423 } |
357 long secs = Long.parseLong(numberText.substring(0, dot)); |
424 try { |
358 numberText = numberText.substring(dot + 1); |
425 parsed = (parsed + "000000000").substring(0, 9); |
359 len = numberText.length(); |
426 return Integer.parseInt(parsed) * negate; |
360 if (len == 0 || len > 9 || numberText.charAt(0) == '-' || numberText.charAt(0) == '+') { |
427 } catch (NumberFormatException | ArithmeticException ex) { |
361 throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2); |
428 throw (DateTimeParseException) new DateTimeParseException("Text cannot be parsed to a Duration: fraction", text, 0).initCause(ex); |
362 } |
429 } |
363 int nanos = Integer.parseInt(numberText); |
430 } |
364 switch (len) { |
431 |
365 case 1: |
432 private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs, long minsAsSecs, long secs, int nanos) { |
366 nanos *= 100000000; |
433 long seconds = Math.addExact(daysAsSecs, Math.addExact(hoursAsSecs, Math.addExact(minsAsSecs, secs))); |
367 break; |
434 if (negate) { |
368 case 2: |
435 return ofSeconds(seconds, nanos).negated(); |
369 nanos *= 10000000; |
436 } |
370 break; |
437 return ofSeconds(seconds, nanos); |
371 case 3: |
|
372 nanos *= 1000000; |
|
373 break; |
|
374 case 4: |
|
375 nanos *= 100000; |
|
376 break; |
|
377 case 5: |
|
378 nanos *= 10000; |
|
379 break; |
|
380 case 6: |
|
381 nanos *= 1000; |
|
382 break; |
|
383 case 7: |
|
384 nanos *= 100; |
|
385 break; |
|
386 case 8: |
|
387 nanos *= 10; |
|
388 break; |
|
389 } |
|
390 return negative ? ofSeconds(secs, -nanos) : create(secs, nanos); |
|
391 |
|
392 } catch (ArithmeticException | NumberFormatException ex) { |
|
393 throw new DateTimeParseException("Duration could not be parsed: " + text, text, 2, ex); |
|
394 } |
|
395 } |
438 } |
396 |
439 |
397 //----------------------------------------------------------------------- |
440 //----------------------------------------------------------------------- |
398 /** |
441 /** |
399 * Obtains an instance of {@code Duration} using seconds and nanoseconds. |
442 * Obtains an instance of {@code Duration} using seconds and nanoseconds. |
420 this.nanos = nanos; |
463 this.nanos = nanos; |
421 } |
464 } |
422 |
465 |
423 //----------------------------------------------------------------------- |
466 //----------------------------------------------------------------------- |
424 /** |
467 /** |
|
468 * Gets the value of the requested unit. |
|
469 * <p> |
|
470 * This returns a value for each of the two supported units, |
|
471 * {@link ChronoUnit#SECONDS SECONDS} and {@link ChronoUnit#NANOS NANOS}. |
|
472 * All other units throw an exception. |
|
473 * |
|
474 * @param unit the {@code TemporalUnit} for which to return the value |
|
475 * @return the long value of the unit |
|
476 * @throws DateTimeException if the unit is not supported |
|
477 */ |
|
478 @Override |
|
479 public long get(TemporalUnit unit) { |
|
480 if (unit == SECONDS) { |
|
481 return seconds; |
|
482 } else if (unit == NANOS) { |
|
483 return nanos; |
|
484 } else { |
|
485 throw new DateTimeException("Unsupported unit: " + unit.getName()); |
|
486 } |
|
487 } |
|
488 |
|
489 /** |
|
490 * Gets the set of units supported by this duration. |
|
491 * <p> |
|
492 * The supported units are {@link ChronoUnit#SECONDS SECONDS}, |
|
493 * and {@link ChronoUnit#NANOS NANOS}. |
|
494 * They are returned in the order seconds, nanos. |
|
495 * <p> |
|
496 * This set can be used in conjunction with {@link #get(TemporalUnit)} |
|
497 * to access the entire state of the period. |
|
498 * |
|
499 * @return a list containing the seconds and nanos units, not null |
|
500 */ |
|
501 @Override |
|
502 public List<TemporalUnit> getUnits() { |
|
503 return DurationUnits.UNITS; |
|
504 } |
|
505 |
|
506 /** |
|
507 * Private class to delay initialization of this list until needed. |
|
508 * The circular dependency between Duration and ChronoUnit prevents |
|
509 * the simple initialization in Duration. |
|
510 */ |
|
511 private static class DurationUnits { |
|
512 final static List<TemporalUnit> UNITS = |
|
513 Collections.unmodifiableList(Arrays.<TemporalUnit>asList(SECONDS, NANOS)); |
|
514 } |
|
515 |
|
516 //----------------------------------------------------------------------- |
|
517 /** |
425 * Checks if this duration is zero length. |
518 * Checks if this duration is zero length. |
426 * <p> |
519 * <p> |
427 * A {@code Duration} represents a directed distance between two points on |
520 * A {@code Duration} represents a directed distance between two points on |
428 * the time-line and can therefore be positive, zero or negative. |
521 * the time-line and can therefore be positive, zero or negative. |
429 * This method checks whether the length is zero. |
522 * This method checks whether the length is zero. |
430 * |
523 * |
431 * @return true if this duration has a total length equal to zero |
524 * @return true if this duration has a total length equal to zero |
432 */ |
525 */ |
433 public boolean isZero() { |
526 public boolean isZero() { |
434 return (seconds | nanos) == 0; |
527 return (seconds | nanos) == 0; |
435 } |
|
436 |
|
437 /** |
|
438 * Checks if this duration is positive, excluding zero. |
|
439 * <p> |
|
440 * A {@code Duration} represents a directed distance between two points on |
|
441 * the time-line and can therefore be positive, zero or negative. |
|
442 * This method checks whether the length is greater than zero. |
|
443 * |
|
444 * @return true if this duration has a total length greater than zero |
|
445 */ |
|
446 public boolean isPositive() { |
|
447 return seconds >= 0 && ((seconds | nanos) != 0); |
|
448 } |
528 } |
449 |
529 |
450 /** |
530 /** |
451 * Checks if this duration is negative, excluding zero. |
531 * Checks if this duration is negative, excluding zero. |
452 * <p> |
532 * <p> |
649 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); |
804 return (amountToSubtract == Long.MIN_VALUE ? plus(Long.MAX_VALUE, unit).plus(1, unit) : plus(-amountToSubtract, unit)); |
650 } |
805 } |
651 |
806 |
652 //----------------------------------------------------------------------- |
807 //----------------------------------------------------------------------- |
653 /** |
808 /** |
|
809 * Returns a copy of this duration with the specified duration in standard 24 hour days subtracted. |
|
810 * <p> |
|
811 * The number of days is multiplied by 86400 to obtain the number of seconds to subtract. |
|
812 * This is based on the standard definition of a day as 24 hours. |
|
813 * <p> |
|
814 * This instance is immutable and unaffected by this method call. |
|
815 * |
|
816 * @param daysToSubtract the days to subtract, positive or negative |
|
817 * @return a {@code Duration} based on this duration with the specified days subtracted, not null |
|
818 * @throws ArithmeticException if numeric overflow occurs |
|
819 */ |
|
820 public Duration minusDays(long daysToSubtract) { |
|
821 return (daysToSubtract == Long.MIN_VALUE ? plusDays(Long.MAX_VALUE).plusDays(1) : plusDays(-daysToSubtract)); |
|
822 } |
|
823 |
|
824 /** |
|
825 * Returns a copy of this duration with the specified duration in hours subtracted. |
|
826 * <p> |
|
827 * The number of hours is multiplied by 3600 to obtain the number of seconds to subtract. |
|
828 * <p> |
|
829 * This instance is immutable and unaffected by this method call. |
|
830 * |
|
831 * @param hoursToSubtract the hours to subtract, positive or negative |
|
832 * @return a {@code Duration} based on this duration with the specified hours subtracted, not null |
|
833 * @throws ArithmeticException if numeric overflow occurs |
|
834 */ |
|
835 public Duration minusHours(long hoursToSubtract) { |
|
836 return (hoursToSubtract == Long.MIN_VALUE ? plusHours(Long.MAX_VALUE).plusHours(1) : plusHours(-hoursToSubtract)); |
|
837 } |
|
838 |
|
839 /** |
|
840 * Returns a copy of this duration with the specified duration in minutes subtracted. |
|
841 * <p> |
|
842 * The number of hours is multiplied by 60 to obtain the number of seconds to subtract. |
|
843 * <p> |
|
844 * This instance is immutable and unaffected by this method call. |
|
845 * |
|
846 * @param minutesToSubtract the minutes to subtract, positive or negative |
|
847 * @return a {@code Duration} based on this duration with the specified minutes subtracted, not null |
|
848 * @throws ArithmeticException if numeric overflow occurs |
|
849 */ |
|
850 public Duration minusMinutes(long minutesToSubtract) { |
|
851 return (minutesToSubtract == Long.MIN_VALUE ? plusMinutes(Long.MAX_VALUE).plusMinutes(1) : plusMinutes(-minutesToSubtract)); |
|
852 } |
|
853 |
|
854 /** |
654 * Returns a copy of this duration with the specified duration in seconds subtracted. |
855 * Returns a copy of this duration with the specified duration in seconds subtracted. |
655 * <p> |
856 * <p> |
656 * This instance is immutable and unaffected by this method call. |
857 * This instance is immutable and unaffected by this method call. |
657 * |
858 * |
658 * @param secondsToSubtract the seconds to subtract, positive or negative |
859 * @param secondsToSubtract the seconds to subtract, positive or negative |
792 * <p> |
992 * <p> |
793 * This returns a temporal object of the same observable type as the input |
993 * This returns a temporal object of the same observable type as the input |
794 * with this duration added. |
994 * with this duration added. |
795 * <p> |
995 * <p> |
796 * In most cases, it is clearer to reverse the calling pattern by using |
996 * In most cases, it is clearer to reverse the calling pattern by using |
797 * {@link Temporal#plus(TemporalAdder)}. |
997 * {@link Temporal#plus(TemporalAmount)}. |
798 * <pre> |
998 * <pre> |
799 * // these two lines are equivalent, but the second approach is recommended |
999 * // these two lines are equivalent, but the second approach is recommended |
800 * dateTime = thisDuration.addTo(dateTime); |
1000 * dateTime = thisDuration.addTo(dateTime); |
801 * dateTime = dateTime.plus(thisDuration); |
1001 * dateTime = dateTime.plus(thisDuration); |
802 * </pre> |
1002 * </pre> |
803 * <p> |
1003 * <p> |
804 * A {@code Duration} can only be added to a {@code Temporal} that |
1004 * The calculation will add the seconds, then nanos. |
805 * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. |
1005 * Only non-zero amounts will be added. |
806 * <p> |
1006 * <p> |
807 * This instance is immutable and unaffected by this method call. |
1007 * This instance is immutable and unaffected by this method call. |
808 * |
1008 * |
809 * @param temporal the temporal object to adjust, not null |
1009 * @param temporal the temporal object to adjust, not null |
810 * @return an object of the same type with the adjustment made, not null |
1010 * @return an object of the same type with the adjustment made, not null |
811 * @throws DateTimeException if unable to add |
1011 * @throws DateTimeException if unable to add |
812 * @throws ArithmeticException if numeric overflow occurs |
1012 * @throws ArithmeticException if numeric overflow occurs |
813 */ |
1013 */ |
814 @Override |
1014 @Override |
815 public Temporal addTo(Temporal temporal) { |
1015 public Temporal addTo(Temporal temporal) { |
816 long instantSecs = temporal.getLong(INSTANT_SECONDS); |
1016 if (seconds != 0) { |
817 long instantNanos = temporal.getLong(NANO_OF_SECOND); |
1017 temporal = temporal.plus(seconds, SECONDS); |
818 instantSecs = Math.addExact(instantSecs, seconds); |
1018 } |
819 instantNanos = Math.addExact(instantNanos, nanos); |
1019 if (nanos != 0) { |
820 instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); |
1020 temporal = temporal.plus(nanos, NANOS); |
821 instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); |
1021 } |
822 return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); |
1022 return temporal; |
823 } |
1023 } |
824 |
1024 |
825 /** |
1025 /** |
826 * Subtracts this duration from the specified temporal object. |
1026 * Subtracts this duration from the specified temporal object. |
827 * <p> |
1027 * <p> |
828 * This returns a temporal object of the same observable type as the input |
1028 * This returns a temporal object of the same observable type as the input |
829 * with this duration subtracted. |
1029 * with this duration subtracted. |
830 * <p> |
1030 * <p> |
831 * In most cases, it is clearer to reverse the calling pattern by using |
1031 * In most cases, it is clearer to reverse the calling pattern by using |
832 * {@link Temporal#minus(TemporalSubtractor)}. |
1032 * {@link Temporal#minus(TemporalAmount)}. |
833 * <pre> |
1033 * <pre> |
834 * // these two lines are equivalent, but the second approach is recommended |
1034 * // these two lines are equivalent, but the second approach is recommended |
835 * dateTime = thisDuration.subtractFrom(dateTime); |
1035 * dateTime = thisDuration.subtractFrom(dateTime); |
836 * dateTime = dateTime.minus(thisDuration); |
1036 * dateTime = dateTime.minus(thisDuration); |
837 * </pre> |
1037 * </pre> |
838 * <p> |
1038 * <p> |
839 * A {@code Duration} can only be subtracted from a {@code Temporal} that |
1039 * The calculation will subtract the seconds, then nanos. |
840 * represents an instant and can supply {@link ChronoField#INSTANT_SECONDS}. |
1040 * Only non-zero amounts will be added. |
841 * <p> |
1041 * <p> |
842 * This instance is immutable and unaffected by this method call. |
1042 * This instance is immutable and unaffected by this method call. |
843 * |
1043 * |
844 * @param temporal the temporal object to adjust, not null |
1044 * @param temporal the temporal object to adjust, not null |
845 * @return an object of the same type with the adjustment made, not null |
1045 * @return an object of the same type with the adjustment made, not null |
846 * @throws DateTimeException if unable to subtract |
1046 * @throws DateTimeException if unable to subtract |
847 * @throws ArithmeticException if numeric overflow occurs |
1047 * @throws ArithmeticException if numeric overflow occurs |
848 */ |
1048 */ |
849 @Override |
1049 @Override |
850 public Temporal subtractFrom(Temporal temporal) { |
1050 public Temporal subtractFrom(Temporal temporal) { |
851 long instantSecs = temporal.getLong(INSTANT_SECONDS); |
1051 if (seconds != 0) { |
852 long instantNanos = temporal.getLong(NANO_OF_SECOND); |
1052 temporal = temporal.minus(seconds, SECONDS); |
853 instantSecs = Math.subtractExact(instantSecs, seconds); |
1053 } |
854 instantNanos = Math.subtractExact(instantNanos, nanos); |
1054 if (nanos != 0) { |
855 instantSecs = Math.addExact(instantSecs, Math.floorDiv(instantNanos, NANOS_PER_SECOND)); |
1055 temporal = temporal.minus(nanos, NANOS); |
856 instantNanos = Math.floorMod(instantNanos, NANOS_PER_SECOND); |
1056 } |
857 return temporal.with(INSTANT_SECONDS, instantSecs).with(NANO_OF_SECOND, instantNanos); |
1057 return temporal; |
858 } |
1058 } |
859 |
1059 |
860 //----------------------------------------------------------------------- |
1060 //----------------------------------------------------------------------- |
|
1061 /** |
|
1062 * Gets the number of minutes in this duration. |
|
1063 * <p> |
|
1064 * This returns the total number of minutes in the duration by dividing the |
|
1065 * number of seconds by 86400. |
|
1066 * This is based on the standard definition of a day as 24 hours. |
|
1067 * <p> |
|
1068 * This instance is immutable and unaffected by this method call. |
|
1069 * |
|
1070 * @return the number of minutes in the duration, may be negative |
|
1071 */ |
|
1072 public long toDays() { |
|
1073 return seconds / SECONDS_PER_DAY; |
|
1074 } |
|
1075 |
|
1076 /** |
|
1077 * Gets the number of minutes in this duration. |
|
1078 * <p> |
|
1079 * This returns the total number of minutes in the duration by dividing the |
|
1080 * number of seconds by 3600. |
|
1081 * <p> |
|
1082 * This instance is immutable and unaffected by this method call. |
|
1083 * |
|
1084 * @return the number of minutes in the duration, may be negative |
|
1085 */ |
|
1086 public long toHours() { |
|
1087 return seconds / SECONDS_PER_HOUR; |
|
1088 } |
|
1089 |
|
1090 /** |
|
1091 * Gets the number of minutes in this duration. |
|
1092 * <p> |
|
1093 * This returns the total number of minutes in the duration by dividing the |
|
1094 * number of seconds by 60. |
|
1095 * <p> |
|
1096 * This instance is immutable and unaffected by this method call. |
|
1097 * |
|
1098 * @return the number of minutes in the duration, may be negative |
|
1099 */ |
|
1100 public long toMinutes() { |
|
1101 return seconds / SECONDS_PER_MINUTE; |
|
1102 } |
|
1103 |
861 /** |
1104 /** |
862 * Converts this duration to the total length in milliseconds. |
1105 * Converts this duration to the total length in milliseconds. |
863 * <p> |
1106 * <p> |
864 * If this duration is too large to fit in a {@code long} milliseconds, then an |
1107 * If this duration is too large to fit in a {@code long} milliseconds, then an |
865 * exception is thrown. |
1108 * exception is thrown. |
968 } |
1187 } |
969 |
1188 |
970 //----------------------------------------------------------------------- |
1189 //----------------------------------------------------------------------- |
971 /** |
1190 /** |
972 * A string representation of this duration using ISO-8601 seconds |
1191 * A string representation of this duration using ISO-8601 seconds |
973 * based representation, such as {@code PT12.345S}. |
1192 * based representation, such as {@code PT8H6M12.345S}. |
974 * <p> |
1193 * <p> |
975 * The format of the returned string will be {@code PTnS} where n is |
1194 * The format of the returned string will be {@code PTnHnMnS}, where n is |
976 * the seconds and fractional seconds of the duration. |
1195 * the relevant hours, minutes or seconds part of the duration. |
|
1196 * Any fractional seconds are placed after a decimal point i the seconds section. |
|
1197 * If a section has a zero value, it is omitted. |
|
1198 * The hours, minutes and seconds will all have the same sign. |
|
1199 * <p> |
|
1200 * Examples: |
|
1201 * <pre> |
|
1202 * "20.345 seconds" -> "PT20.345S |
|
1203 * "15 minutes" (15 * 60 seconds) -> "PT15M" |
|
1204 * "10 hours" (10 * 3600 seconds) -> "PT10H" |
|
1205 * "2 days" (2 * 86400 seconds) -> "PT48H" |
|
1206 * </pre> |
|
1207 * Note that multiples of 24 hours are not output as days to avoid confusion |
|
1208 * with {@code Period}. |
977 * |
1209 * |
978 * @return an ISO-8601 representation of this duration, not null |
1210 * @return an ISO-8601 representation of this duration, not null |
979 */ |
1211 */ |
980 @Override |
1212 @Override |
981 public String toString() { |
1213 public String toString() { |
|
1214 if (this == ZERO) { |
|
1215 return "PT0S"; |
|
1216 } |
|
1217 long hours = seconds / SECONDS_PER_HOUR; |
|
1218 int minutes = (int) ((seconds % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE); |
|
1219 int secs = (int) (seconds % SECONDS_PER_MINUTE); |
982 StringBuilder buf = new StringBuilder(24); |
1220 StringBuilder buf = new StringBuilder(24); |
983 buf.append("PT"); |
1221 buf.append("PT"); |
984 if (seconds < 0 && nanos > 0) { |
1222 if (hours != 0) { |
985 if (seconds == -1) { |
1223 buf.append(hours).append('H'); |
|
1224 } |
|
1225 if (minutes != 0) { |
|
1226 buf.append(minutes).append('M'); |
|
1227 } |
|
1228 if (secs == 0 && nanos == 0 && buf.length() > 2) { |
|
1229 return buf.toString(); |
|
1230 } |
|
1231 if (secs < 0 && nanos > 0) { |
|
1232 if (secs == -1) { |
986 buf.append("-0"); |
1233 buf.append("-0"); |
987 } else { |
1234 } else { |
988 buf.append(seconds + 1); |
1235 buf.append(secs + 1); |
989 } |
1236 } |
990 } else { |
1237 } else { |
991 buf.append(seconds); |
1238 buf.append(secs); |
992 } |
1239 } |
993 if (nanos > 0) { |
1240 if (nanos > 0) { |
994 int pos = buf.length(); |
1241 int pos = buf.length(); |
995 if (seconds < 0) { |
1242 if (secs < 0) { |
996 buf.append(2 * NANOS_PER_SECOND - nanos); |
1243 buf.append(2 * NANOS_PER_SECOND - nanos); |
997 } else { |
1244 } else { |
998 buf.append(nanos + NANOS_PER_SECOND); |
1245 buf.append(nanos + NANOS_PER_SECOND); |
999 } |
1246 } |
1000 while (buf.charAt(buf.length() - 1) == '0') { |
1247 while (buf.charAt(buf.length() - 1) == '0') { |