1 /*
2 * Copyright 2001-2010 Stephen Colebourne
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.joda.time;
17
18 import java.io.Serializable;
19
20 import org.joda.convert.FromString;
21 import org.joda.time.base.BasePeriod;
22 import org.joda.time.chrono.ISOChronology;
23 import org.joda.time.field.FieldUtils;
24 import org.joda.time.format.ISOPeriodFormat;
25 import org.joda.time.format.PeriodFormatter;
26
27 /**
28 * An immutable time period specifying a set of duration field values.
29 * <p>
30 * A time period is divided into a number of fields, such as hours and seconds.
31 * Which fields are supported is defined by the PeriodType class.
32 * The default is the standard period type, which supports years, months, weeks, days,
33 * hours, minutes, seconds and millis.
34 * <p>
35 * When this time period is added to an instant, the effect is of adding each field in turn.
36 * As a result, this takes into account daylight savings time.
37 * Adding a time period of 1 day to the day before daylight savings starts will only add
38 * 23 hours rather than 24 to ensure that the time remains the same.
39 * If this is not the behaviour you want, then see {@link Duration}.
40 * <p>
41 * The definition of a period also affects the equals method. A period of 1
42 * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes.
43 * This is because periods represent an abstracted definition of a time period
44 * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight
45 * savings boundary). To compare the actual duration of two periods, convert
46 * both to durations using toDuration, an operation that emphasises that the
47 * result may differ according to the date you choose.
48 * <p>
49 * Period is thread-safe and immutable, provided that the PeriodType is as well.
50 * All standard PeriodType classes supplied are thread-safe and immutable.
51 *
52 * @author Brian S O'Neill
53 * @author Stephen Colebourne
54 * @since 1.0
55 * @see MutablePeriod
56 */
57 public final class Period
58 extends BasePeriod
59 implements ReadablePeriod, Serializable {
60
61 /**
62 * A period of zero length and standard period type.
63 * @since 1.4
64 */
65 public static final Period ZERO = new Period();
66
67 /** Serialization version */
68 private static final long serialVersionUID = 741052353876488155L;
69
70 //-----------------------------------------------------------------------
71 /**
72 * Parses a {@code Period} from the specified string.
73 * <p>
74 * This uses {@link ISOPeriodFormat#standard()}.
75 *
76 * @param str the string to parse, not null
77 * @since 2.0
78 */
79 @FromString
80 public static Period parse(String str) {
81 return parse(str, ISOPeriodFormat.standard());
82 }
83
84 /**
85 * Parses a {@code Period} from the specified string using a formatter.
86 *
87 * @param str the string to parse, not null
88 * @param formatter the formatter to use, not null
89 * @since 2.0
90 */
91 public static Period parse(String str, PeriodFormatter formatter) {
92 return formatter.parsePeriod(str);
93 }
94
95 //-----------------------------------------------------------------------
96 /**
97 * Create a period with a specified number of years.
98 * <p>
99 * The standard period type is used, thus you can add other fields such
100 * as months or days using the <code>withXxx()</code> methods.
101 * For example, <code>Period.years(2).withMonths(6);</code>
102 * <p>
103 * If you want a year-based period that cannot have other fields added,
104 * then you should consider using {@link Years}.
105 *
106 * @param years the amount of years in this period
107 * @return the period
108 */
109 public static Period years(int years) {
110 return new Period(new int[] {years, 0, 0, 0, 0, 0, 0, 0, 0}, PeriodType.standard());
111 }
112
113 /**
114 * Create a period with a specified number of months.
115 * <p>
116 * The standard period type is used, thus you can add other fields such
117 * as years or days using the <code>withXxx()</code> methods.
118 * For example, <code>Period.months(2).withDays(6);</code>
119 * <p>
120 * If you want a month-based period that cannot have other fields added,
121 * then you should consider using {@link Months}.
122 *
123 * @param months the amount of months in this period
124 * @return the period
125 */
126 public static Period months(int months) {
127 return new Period(new int[] {0, months, 0, 0, 0, 0, 0, 0}, PeriodType.standard());
128 }
129
130 /**
131 * Create a period with a specified number of weeks.
132 * <p>
133 * The standard period type is used, thus you can add other fields such
134 * as months or days using the <code>withXxx()</code> methods.
135 * For example, <code>Period.weeks(2).withDays(6);</code>
136 * <p>
137 * If you want a week-based period that cannot have other fields added,
138 * then you should consider using {@link Weeks}.
139 *
140 * @param weeks the amount of weeks in this period
141 * @return the period
142 */
143 public static Period weeks(int weeks) {
144 return new Period(new int[] {0, 0, weeks, 0, 0, 0, 0, 0}, PeriodType.standard());
145 }
146
147 /**
148 * Create a period with a specified number of days.
149 * <p>
150 * The standard period type is used, thus you can add other fields such
151 * as months or weeks using the <code>withXxx()</code> methods.
152 * For example, <code>Period.days(2).withHours(6);</code>
153 * <p>
154 * If you want a day-based period that cannot have other fields added,
155 * then you should consider using {@link Days}.
156 *
157 * @param days the amount of days in this period
158 * @return the period
159 */
160 public static Period days(int days) {
161 return new Period(new int[] {0, 0, 0, days, 0, 0, 0, 0}, PeriodType.standard());
162 }
163
164 /**
165 * Create a period with a specified number of hours.
166 * <p>
167 * The standard period type is used, thus you can add other fields such
168 * as months or days using the <code>withXxx()</code> methods.
169 * For example, <code>Period.hours(2).withMinutes(30);</code>
170 * <p>
171 * If you want a hour-based period that cannot have other fields added,
172 * then you should consider using {@link Hours}.
173 *
174 * @param hours the amount of hours in this period
175 * @return the period
176 */
177 public static Period hours(int hours) {
178 return new Period(new int[] {0, 0, 0, 0, hours, 0, 0, 0}, PeriodType.standard());
179 }
180
181 /**
182 * Create a period with a specified number of minutes.
183 * <p>
184 * The standard period type is used, thus you can add other fields such
185 * as days or hours using the <code>withXxx()</code> methods.
186 * For example, <code>Period.minutes(2).withSeconds(30);</code>
187 * <p>
188 * If you want a minute-based period that cannot have other fields added,
189 * then you should consider using {@link Minutes}.
190 *
191 * @param minutes the amount of minutes in this period
192 * @return the period
193 */
194 public static Period minutes(int minutes) {
195 return new Period(new int[] {0, 0, 0, 0, 0, minutes, 0, 0}, PeriodType.standard());
196 }
197
198 /**
199 * Create a period with a specified number of seconds.
200 * <p>
201 * The standard period type is used, thus you can add other fields such
202 * as days or hours using the <code>withXxx()</code> methods.
203 * For example, <code>Period.seconds(2).withMillis(30);</code>
204 * <p>
205 * If you want a second-based period that cannot have other fields added,
206 * then you should consider using {@link Seconds}.
207 *
208 * @param seconds the amount of seconds in this period
209 * @return the period
210 */
211 public static Period seconds(int seconds) {
212 return new Period(new int[] {0, 0, 0, 0, 0, 0, seconds, 0}, PeriodType.standard());
213 }
214
215 /**
216 * Create a period with a specified number of millis.
217 * <p>
218 * The standard period type is used, thus you can add other fields such
219 * as days or hours using the <code>withXxx()</code> methods.
220 * For example, <code>Period.millis(20).withSeconds(30);</code>
221 *
222 * @param millis the amount of millis in this period
223 * @return the period
224 */
225 public static Period millis(int millis) {
226 return new Period(new int[] {0, 0, 0, 0, 0, 0, 0, millis}, PeriodType.standard());
227 }
228
229 //-----------------------------------------------------------------------
230 /**
231 * Creates a period from two partially specified times, calculating
232 * by field difference.
233 * <p>
234 * The two partials must contain the same fields, thus you can specify
235 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
236 * but not one of each. Also, the partial may not contain overlapping
237 * fields, such as dayOfWeek and dayOfMonth.
238 * <p>
239 * Calculation by field difference works by extracting the difference
240 * one field at a time and not wrapping into other fields.
241 * Thus 2005-06-09/2007-04-12 will yield P1Y-2M3D.
242 * <p>
243 * For example, you have an event that always runs from the 27th of
244 * each month to the 2nd of the next month. If you calculate this
245 * period using a standard constructor, then you will get between
246 * P3D and P6D depending on the month. If you use this method, then
247 * you will get P1M-25D. This field-difference based period can
248 * be successfully applied to each month of the year to obtain the
249 * correct end date for a given start date.
250 *
251 * @param start the start of the period, must not be null
252 * @param end the end of the period, must not be null
253 * @throws IllegalArgumentException if the partials are null or invalid
254 * @since 1.1
255 */
256 public static Period fieldDifference(ReadablePartial start, ReadablePartial end) {
257 if (start == null || end == null) {
258 throw new IllegalArgumentException("ReadablePartial objects must not be null");
259 }
260 if (start.size() != end.size()) {
261 throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields");
262 }
263 DurationFieldType[] types = new DurationFieldType[start.size()];
264 int[] values = new int[start.size()];
265 for (int i = 0, isize = start.size(); i < isize; i++) {
266 if (start.getFieldType(i) != end.getFieldType(i)) {
267 throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields");
268 }
269 types[i] = start.getFieldType(i).getDurationType();
270 if (i > 0 && types[i - 1] == types[i]) {
271 throw new IllegalArgumentException("ReadablePartial objects must not have overlapping fields");
272 }
273 values[i] = end.getValue(i) - start.getValue(i);
274 }
275 return new Period(values, PeriodType.forFields(types));
276 }
277
278 //-----------------------------------------------------------------------
279 /**
280 * Creates a new empty period with the standard set of fields.
281 * <p>
282 * One way to initialise a period is as follows:
283 * <pre>
284 * Period = new Period().withYears(6).withMonths(3).withSeconds(23);
285 * </pre>
286 * Bear in mind that this creates four period instances in total, three of
287 * which are immediately discarded.
288 * The alterative is more efficient, but less readable:
289 * <pre>
290 * Period = new Period(6, 3, 0, 0, 0, 0, 23, 0);
291 * </pre>
292 * The following is also slightly less wasteful:
293 * <pre>
294 * Period = Period.years(6).withMonths(3).withSeconds(23);
295 * </pre>
296 */
297 public Period() {
298 super(0L, null, null);
299 }
300
301 /**
302 * Create a period from a set of field values using the standard set of fields.
303 * Note that the parameters specify the time fields hours, minutes,
304 * seconds and millis, not the date fields.
305 *
306 * @param hours amount of hours in this period
307 * @param minutes amount of minutes in this period
308 * @param seconds amount of seconds in this period
309 * @param millis amount of milliseconds in this period
310 */
311 public Period(int hours, int minutes, int seconds, int millis) {
312 super(0, 0, 0, 0, hours, minutes, seconds, millis, PeriodType.standard());
313 }
314
315 /**
316 * Create a period from a set of field values using the standard set of fields.
317 *
318 * @param years amount of years in this period
319 * @param months amount of months in this period
320 * @param weeks amount of weeks in this period
321 * @param days amount of days in this period
322 * @param hours amount of hours in this period
323 * @param minutes amount of minutes in this period
324 * @param seconds amount of seconds in this period
325 * @param millis amount of milliseconds in this period
326 */
327 public Period(int years, int months, int weeks, int days,
328 int hours, int minutes, int seconds, int millis) {
329 super(years, months, weeks, days, hours, minutes, seconds, millis, PeriodType.standard());
330 }
331
332 /**
333 * Create a period from a set of field values.
334 * <p>
335 * There is usually little need to use this constructor.
336 * The period type is used primarily to define how to split an interval into a period.
337 * As this constructor already is split, the period type does no real work.
338 *
339 * @param years amount of years in this period, which must be zero if unsupported
340 * @param months amount of months in this period, which must be zero if unsupported
341 * @param weeks amount of weeks in this period, which must be zero if unsupported
342 * @param days amount of days in this period, which must be zero if unsupported
343 * @param hours amount of hours in this period, which must be zero if unsupported
344 * @param minutes amount of minutes in this period, which must be zero if unsupported
345 * @param seconds amount of seconds in this period, which must be zero if unsupported
346 * @param millis amount of milliseconds in this period, which must be zero if unsupported
347 * @param type which set of fields this period supports, null means AllType
348 * @throws IllegalArgumentException if an unsupported field's value is non-zero
349 */
350 public Period(int years, int months, int weeks, int days,
351 int hours, int minutes, int seconds, int millis, PeriodType type) {
352 super(years, months, weeks, days, hours, minutes, seconds, millis, type);
353 }
354
355 /**
356 * Creates a period from the given millisecond duration using the standard
357 * set of fields.
358 * <p>
359 * Only precise fields in the period type will be used.
360 * For the standard period type this is the time fields only.
361 * Thus the year, month, week and day fields will not be populated.
362 * <p>
363 * If the duration is small, less than one day, then this method will perform
364 * as you might expect and split the fields evenly.
365 * <p>
366 * If the duration is larger than one day then all the remaining duration will
367 * be stored in the largest available precise field, hours in this case.
368 * <p>
369 * For example, a duration equal to (365 + 60 + 5) days will be converted to
370 * ((365 + 60 + 5) * 24) hours by this constructor.
371 * <p>
372 * For more control over the conversion process, you have two options:
373 * <ul>
374 * <li>convert the duration to an {@link Interval}, and from there obtain the period
375 * <li>specify a period type that contains precise definitions of the day and larger
376 * fields, such as UTC
377 * </ul>
378 *
379 * @param duration the duration, in milliseconds
380 */
381 public Period(long duration) {
382 super(duration);
383 }
384
385 /**
386 * Creates a period from the given millisecond duration.
387 * <p>
388 * Only precise fields in the period type will be used.
389 * Imprecise fields will not be populated.
390 * <p>
391 * If the duration is small then this method will perform
392 * as you might expect and split the fields evenly.
393 * <p>
394 * If the duration is large then all the remaining duration will
395 * be stored in the largest available precise field.
396 * For details as to which fields are precise, review the period type javadoc.
397 *
398 * @param duration the duration, in milliseconds
399 * @param type which set of fields this period supports, null means standard
400 */
401 public Period(long duration, PeriodType type) {
402 super(duration, type, null);
403 }
404
405 /**
406 * Creates a period from the given millisecond duration using the standard
407 * set of fields.
408 * <p>
409 * Only precise fields in the period type will be used.
410 * Imprecise fields will not be populated.
411 * <p>
412 * If the duration is small then this method will perform
413 * as you might expect and split the fields evenly.
414 * <p>
415 * If the duration is large then all the remaining duration will
416 * be stored in the largest available precise field.
417 * For details as to which fields are precise, review the period type javadoc.
418 *
419 * @param duration the duration, in milliseconds
420 * @param chronology the chronology to use to split the duration, null means ISO default
421 */
422 public Period(long duration, Chronology chronology) {
423 super(duration, null, chronology);
424 }
425
426 /**
427 * Creates a period from the given millisecond duration.
428 * <p>
429 * Only precise fields in the period type will be used.
430 * Imprecise fields will not be populated.
431 * <p>
432 * If the duration is small then this method will perform
433 * as you might expect and split the fields evenly.
434 * <p>
435 * If the duration is large then all the remaining duration will
436 * be stored in the largest available precise field.
437 * For details as to which fields are precise, review the period type javadoc.
438 *
439 * @param duration the duration, in milliseconds
440 * @param type which set of fields this period supports, null means standard
441 * @param chronology the chronology to use to split the duration, null means ISO default
442 */
443 public Period(long duration, PeriodType type, Chronology chronology) {
444 super(duration, type, chronology);
445 }
446
447 /**
448 * Creates a period from the given interval endpoints using the standard
449 * set of fields.
450 *
451 * @param startInstant interval start, in milliseconds
452 * @param endInstant interval end, in milliseconds
453 */
454 public Period(long startInstant, long endInstant) {
455 super(startInstant, endInstant, null, null);
456 }
457
458 /**
459 * Creates a period from the given interval endpoints.
460 *
461 * @param startInstant interval start, in milliseconds
462 * @param endInstant interval end, in milliseconds
463 * @param type which set of fields this period supports, null means standard
464 */
465 public Period(long startInstant, long endInstant, PeriodType type) {
466 super(startInstant, endInstant, type, null);
467 }
468
469 /**
470 * Creates a period from the given interval endpoints using the standard
471 * set of fields.
472 *
473 * @param startInstant interval start, in milliseconds
474 * @param endInstant interval end, in milliseconds
475 * @param chrono the chronology to use, null means ISO in default zone
476 */
477 public Period(long startInstant, long endInstant, Chronology chrono) {
478 super(startInstant, endInstant, null, chrono);
479 }
480
481 /**
482 * Creates a period from the given interval endpoints.
483 *
484 * @param startInstant interval start, in milliseconds
485 * @param endInstant interval end, in milliseconds
486 * @param type which set of fields this period supports, null means standard
487 * @param chrono the chronology to use, null means ISO in default zone
488 */
489 public Period(long startInstant, long endInstant, PeriodType type, Chronology chrono) {
490 super(startInstant, endInstant, type, chrono);
491 }
492
493 /**
494 * Creates a period from the given interval endpoints using the standard
495 * set of fields.
496 *
497 * @param startInstant interval start, null means now
498 * @param endInstant interval end, null means now
499 */
500 public Period(ReadableInstant startInstant, ReadableInstant endInstant) {
501 super(startInstant, endInstant, null);
502 }
503
504 /**
505 * Creates a period from the given interval endpoints.
506 *
507 * @param startInstant interval start, null means now
508 * @param endInstant interval end, null means now
509 * @param type which set of fields this period supports, null means standard
510 */
511 public Period(ReadableInstant startInstant, ReadableInstant endInstant, PeriodType type) {
512 super(startInstant, endInstant, type);
513 }
514
515 /**
516 * Creates a period from two partially specified times.
517 * <p>
518 * The two partials must contain the same fields, thus you can specify
519 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
520 * but not one of each.
521 * As these are Partial objects, time zones have no effect on the result.
522 * <p>
523 * The two partials must also both be contiguous - see
524 * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
525 * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous.
526 * <p>
527 * An alternative way of constructing a Period from two Partials
528 * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}.
529 * That method handles all kinds of partials.
530 *
531 * @param start the start of the period, must not be null
532 * @param end the end of the period, must not be null
533 * @throws IllegalArgumentException if the partials are null or invalid
534 * @since 1.1
535 */
536 public Period(ReadablePartial start, ReadablePartial end) {
537 super(start, end, null);
538 }
539
540 /**
541 * Creates a period from two partially specified times.
542 * <p>
543 * The two partials must contain the same fields, thus you can specify
544 * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
545 * but not one of each.
546 * As these are Partial objects, time zones have no effect on the result.
547 * <p>
548 * The two partials must also both be contiguous - see
549 * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
550 * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous.
551 * <p>
552 * An alternative way of constructing a Period from two Partials
553 * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}.
554 * That method handles all kinds of partials.
555 *
556 * @param start the start of the period, must not be null
557 * @param end the end of the period, must not be null
558 * @param type which set of fields this period supports, null means standard
559 * @throws IllegalArgumentException if the partials are null or invalid
560 * @since 1.1
561 */
562 public Period(ReadablePartial start, ReadablePartial end, PeriodType type) {
563 super(start, end, type);
564 }
565
566 /**
567 * Creates a period from the given start point and the duration.
568 *
569 * @param startInstant the interval start, null means now
570 * @param duration the duration of the interval, null means zero-length
571 */
572 public Period(ReadableInstant startInstant, ReadableDuration duration) {
573 super(startInstant, duration, null);
574 }
575
576 /**
577 * Creates a period from the given start point and the duration.
578 *
579 * @param startInstant the interval start, null means now
580 * @param duration the duration of the interval, null means zero-length
581 * @param type which set of fields this period supports, null means standard
582 */
583 public Period(ReadableInstant startInstant, ReadableDuration duration, PeriodType type) {
584 super(startInstant, duration, type);
585 }
586
587 /**
588 * Creates a period from the given duration and end point.
589 *
590 * @param duration the duration of the interval, null means zero-length
591 * @param endInstant the interval end, null means now
592 */
593 public Period(ReadableDuration duration, ReadableInstant endInstant) {
594 super(duration, endInstant, null);
595 }
596
597 /**
598 * Creates a period from the given duration and end point.
599 *
600 * @param duration the duration of the interval, null means zero-length
601 * @param endInstant the interval end, null means now
602 * @param type which set of fields this period supports, null means standard
603 */
604 public Period(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) {
605 super(duration, endInstant, type);
606 }
607
608 /**
609 * Creates a period by converting or copying from another object.
610 * <p>
611 * The recognised object types are defined in
612 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
613 * include ReadablePeriod, ReadableInterval and String.
614 * The String formats are described by {@link ISOPeriodFormat#standard()}.
615 *
616 * @param period period to convert
617 * @throws IllegalArgumentException if period is invalid
618 * @throws UnsupportedOperationException if an unsupported field's value is non-zero
619 */
620 public Period(Object period) {
621 super(period, null, null);
622 }
623
624 /**
625 * Creates a period by converting or copying from another object.
626 * <p>
627 * The recognised object types are defined in
628 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
629 * include ReadablePeriod, ReadableInterval and String.
630 * The String formats are described by {@link ISOPeriodFormat#standard()}.
631 *
632 * @param period period to convert
633 * @param type which set of fields this period supports, null means use converter
634 * @throws IllegalArgumentException if period is invalid
635 * @throws UnsupportedOperationException if an unsupported field's value is non-zero
636 */
637 public Period(Object period, PeriodType type) {
638 super(period, type, null);
639 }
640
641 /**
642 * Creates a period by converting or copying from another object.
643 * <p>
644 * The recognised object types are defined in
645 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
646 * include ReadablePeriod, ReadableInterval and String.
647 * The String formats are described by {@link ISOPeriodFormat#standard()}.
648 *
649 * @param period period to convert
650 * @param chrono the chronology to use, null means ISO in default zone
651 * @throws IllegalArgumentException if period is invalid
652 * @throws UnsupportedOperationException if an unsupported field's value is non-zero
653 */
654 public Period(Object period, Chronology chrono) {
655 super(period, null, chrono);
656 }
657
658 /**
659 * Creates a period by converting or copying from another object.
660 * <p>
661 * The recognised object types are defined in
662 * {@link org.joda.time.convert.ConverterManager ConverterManager} and
663 * include ReadablePeriod, ReadableInterval and String.
664 * The String formats are described by {@link ISOPeriodFormat#standard()}.
665 *
666 * @param period period to convert
667 * @param type which set of fields this period supports, null means use converter
668 * @param chrono the chronology to use, null means ISO in default zone
669 * @throws IllegalArgumentException if period is invalid
670 * @throws UnsupportedOperationException if an unsupported field's value is non-zero
671 */
672 public Period(Object period, PeriodType type, Chronology chrono) {
673 super(period, type, chrono);
674 }
675
676 /**
677 * Constructor used when we trust ourselves.
678 *
679 * @param values the values to use, not null, not cloned
680 * @param type which set of fields this period supports, not null
681 */
682 private Period(int[] values, PeriodType type) {
683 super(values, type);
684 }
685
686 //-----------------------------------------------------------------------
687 /**
688 * Get this period as an immutable <code>Period</code> object
689 * by returning <code>this</code>.
690 *
691 * @return <code>this</code>
692 */
693 public Period toPeriod() {
694 return this;
695 }
696
697 //-----------------------------------------------------------------------
698 /**
699 * Gets the years field part of the period.
700 *
701 * @return the number of years in the period, zero if unsupported
702 */
703 public int getYears() {
704 return getPeriodType().getIndexedField(this, PeriodType.YEAR_INDEX);
705 }
706
707 /**
708 * Gets the months field part of the period.
709 *
710 * @return the number of months in the period, zero if unsupported
711 */
712 public int getMonths() {
713 return getPeriodType().getIndexedField(this, PeriodType.MONTH_INDEX);
714 }
715
716 /**
717 * Gets the weeks field part of the period.
718 *
719 * @return the number of weeks in the period, zero if unsupported
720 */
721 public int getWeeks() {
722 return getPeriodType().getIndexedField(this, PeriodType.WEEK_INDEX);
723 }
724
725 /**
726 * Gets the days field part of the period.
727 *
728 * @return the number of days in the period, zero if unsupported
729 */
730 public int getDays() {
731 return getPeriodType().getIndexedField(this, PeriodType.DAY_INDEX);
732 }
733
734 //-----------------------------------------------------------------------
735 /**
736 * Gets the hours field part of the period.
737 *
738 * @return the number of hours in the period, zero if unsupported
739 */
740 public int getHours() {
741 return getPeriodType().getIndexedField(this, PeriodType.HOUR_INDEX);
742 }
743
744 /**
745 * Gets the minutes field part of the period.
746 *
747 * @return the number of minutes in the period, zero if unsupported
748 */
749 public int getMinutes() {
750 return getPeriodType().getIndexedField(this, PeriodType.MINUTE_INDEX);
751 }
752
753 /**
754 * Gets the seconds field part of the period.
755 *
756 * @return the number of seconds in the period, zero if unsupported
757 */
758 public int getSeconds() {
759 return getPeriodType().getIndexedField(this, PeriodType.SECOND_INDEX);
760 }
761
762 /**
763 * Gets the millis field part of the period.
764 *
765 * @return the number of millis in the period, zero if unsupported
766 */
767 public int getMillis() {
768 return getPeriodType().getIndexedField(this, PeriodType.MILLI_INDEX);
769 }
770
771 //-----------------------------------------------------------------------
772 /**
773 * Creates a new Period instance with the same field values but
774 * different PeriodType.
775 * <p>
776 * This period instance is immutable and unaffected by this method call.
777 *
778 * @param type the period type to use, null means standard
779 * @return the new period instance
780 * @throws IllegalArgumentException if the new period won't accept all of the current fields
781 */
782 public Period withPeriodType(PeriodType type) {
783 type = DateTimeUtils.getPeriodType(type);
784 if (type.equals(getPeriodType())) {
785 return this;
786 }
787 return new Period(this, type);
788 }
789
790 /**
791 * Creates a new Period instance with the fields from the specified period
792 * copied on top of those from this period.
793 * <p>
794 * This period instance is immutable and unaffected by this method call.
795 *
796 * @param period the period to copy from, null ignored
797 * @return the new period instance
798 * @throws IllegalArgumentException if a field type is unsupported
799 */
800 public Period withFields(ReadablePeriod period) {
801 if (period == null) {
802 return this;
803 }
804 int[] newValues = getValues(); // cloned
805 newValues = super.mergePeriodInto(newValues, period);
806 return new Period(newValues, getPeriodType());
807 }
808
809 //-----------------------------------------------------------------------
810 /**
811 * Creates a new Period instance with the specified field set to a new value.
812 * <p>
813 * This period instance is immutable and unaffected by this method call.
814 *
815 * @param field the field to set, not null
816 * @param value the value to set to
817 * @return the new period instance
818 * @throws IllegalArgumentException if the field type is null or unsupported
819 */
820 public Period withField(DurationFieldType field, int value) {
821 if (field == null) {
822 throw new IllegalArgumentException("Field must not be null");
823 }
824 int[] newValues = getValues(); // cloned
825 super.setFieldInto(newValues, field, value);
826 return new Period(newValues, getPeriodType());
827 }
828
829 /**
830 * Creates a new Period instance with the valueToAdd added to the specified field.
831 * <p>
832 * This period instance is immutable and unaffected by this method call.
833 *
834 * @param field the field to set, not null
835 * @param value the value to add
836 * @return the new period instance
837 * @throws IllegalArgumentException if the field type is null or unsupported
838 */
839 public Period withFieldAdded(DurationFieldType field, int value) {
840 if (field == null) {
841 throw new IllegalArgumentException("Field must not be null");
842 }
843 if (value == 0) {
844 return this;
845 }
846 int[] newValues = getValues(); // cloned
847 super.addFieldInto(newValues, field, value);
848 return new Period(newValues, getPeriodType());
849 }
850
851 //-----------------------------------------------------------------------
852 /**
853 * Returns a new period with the specified number of years.
854 * <p>
855 * This period instance is immutable and unaffected by this method call.
856 *
857 * @param years the amount of years to add, may be negative
858 * @return the new period with the increased years
859 * @throws UnsupportedOperationException if the field is not supported
860 */
861 public Period withYears(int years) {
862 int[] values = getValues(); // cloned
863 getPeriodType().setIndexedField(this, PeriodType.YEAR_INDEX, values, years);
864 return new Period(values, getPeriodType());
865 }
866
867 /**
868 * Returns a new period with the specified number of months.
869 * <p>
870 * This period instance is immutable and unaffected by this method call.
871 *
872 * @param months the amount of months to add, may be negative
873 * @return the new period with the increased months
874 * @throws UnsupportedOperationException if the field is not supported
875 */
876 public Period withMonths(int months) {
877 int[] values = getValues(); // cloned
878 getPeriodType().setIndexedField(this, PeriodType.MONTH_INDEX, values, months);
879 return new Period(values, getPeriodType());
880 }
881
882 /**
883 * Returns a new period with the specified number of weeks.
884 * <p>
885 * This period instance is immutable and unaffected by this method call.
886 *
887 * @param weeks the amount of weeks to add, may be negative
888 * @return the new period with the increased weeks
889 * @throws UnsupportedOperationException if the field is not supported
890 */
891 public Period withWeeks(int weeks) {
892 int[] values = getValues(); // cloned
893 getPeriodType().setIndexedField(this, PeriodType.WEEK_INDEX, values, weeks);
894 return new Period(values, getPeriodType());
895 }
896
897 /**
898 * Returns a new period with the specified number of days.
899 * <p>
900 * This period instance is immutable and unaffected by this method call.
901 *
902 * @param days the amount of days to add, may be negative
903 * @return the new period with the increased days
904 * @throws UnsupportedOperationException if the field is not supported
905 */
906 public Period withDays(int days) {
907 int[] values = getValues(); // cloned
908 getPeriodType().setIndexedField(this, PeriodType.DAY_INDEX, values, days);
909 return new Period(values, getPeriodType());
910 }
911
912 /**
913 * Returns a new period with the specified number of hours.
914 * <p>
915 * This period instance is immutable and unaffected by this method call.
916 *
917 * @param hours the amount of hours to add, may be negative
918 * @return the new period with the increased hours
919 * @throws UnsupportedOperationException if the field is not supported
920 */
921 public Period withHours(int hours) {
922 int[] values = getValues(); // cloned
923 getPeriodType().setIndexedField(this, PeriodType.HOUR_INDEX, values, hours);
924 return new Period(values, getPeriodType());
925 }
926
927 /**
928 * Returns a new period with the specified number of minutes.
929 * <p>
930 * This period instance is immutable and unaffected by this method call.
931 *
932 * @param minutes the amount of minutes to add, may be negative
933 * @return the new period with the increased minutes
934 * @throws UnsupportedOperationException if the field is not supported
935 */
936 public Period withMinutes(int minutes) {
937 int[] values = getValues(); // cloned
938 getPeriodType().setIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes);
939 return new Period(values, getPeriodType());
940 }
941
942 /**
943 * Returns a new period with the specified number of seconds.
944 * <p>
945 * This period instance is immutable and unaffected by this method call.
946 *
947 * @param seconds the amount of seconds to add, may be negative
948 * @return the new period with the increased seconds
949 * @throws UnsupportedOperationException if the field is not supported
950 */
951 public Period withSeconds(int seconds) {
952 int[] values = getValues(); // cloned
953 getPeriodType().setIndexedField(this, PeriodType.SECOND_INDEX, values, seconds);
954 return new Period(values, getPeriodType());
955 }
956
957 /**
958 * Returns a new period with the specified number of millis.
959 * <p>
960 * This period instance is immutable and unaffected by this method call.
961 *
962 * @param millis the amount of millis to add, may be negative
963 * @return the new period with the increased millis
964 * @throws UnsupportedOperationException if the field is not supported
965 */
966 public Period withMillis(int millis) {
967 int[] values = getValues(); // cloned
968 getPeriodType().setIndexedField(this, PeriodType.MILLI_INDEX, values, millis);
969 return new Period(values, getPeriodType());
970 }
971
972 //-----------------------------------------------------------------------
973 /**
974 * Returns a new period with the specified period added.
975 * <p>
976 * Each field of the period is added separately. Thus a period of
977 * 2 hours 30 minutes plus 3 hours 40 minutes will produce a result
978 * of 5 hours 70 minutes - see {@link #normalizedStandard()}.
979 * <p>
980 * If the period being added contains a non-zero amount for a field that
981 * is not supported in this period then an exception is thrown.
982 * <p>
983 * This period instance is immutable and unaffected by this method call.
984 *
985 * @param period the period to add, null adds zero and returns this
986 * @return the new updated period
987 * @throws UnsupportedOperationException if any field is not supported
988 * @since 1.5
989 */
990 public Period plus(ReadablePeriod period) {
991 if (period == null) {
992 return this;
993 }
994 int[] values = getValues(); // cloned
995 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, period.get(DurationFieldType.YEARS_TYPE));
996 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, period.get(DurationFieldType.MONTHS_TYPE));
997 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, period.get(DurationFieldType.WEEKS_TYPE));
998 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, period.get(DurationFieldType.DAYS_TYPE));
999 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, period.get(DurationFieldType.HOURS_TYPE));
1000 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, period.get(DurationFieldType.MINUTES_TYPE));
1001 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, period.get(DurationFieldType.SECONDS_TYPE));
1002 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, period.get(DurationFieldType.MILLIS_TYPE));
1003 return new Period(values, getPeriodType());
1004 }
1005
1006 //-----------------------------------------------------------------------
1007 /**
1008 * Returns a new period with the specified number of years added.
1009 * <p>
1010 * This period instance is immutable and unaffected by this method call.
1011 *
1012 * @param years the amount of years to add, may be negative
1013 * @return the new period with the increased years
1014 * @throws UnsupportedOperationException if the field is not supported
1015 */
1016 public Period plusYears(int years) {
1017 if (years == 0) {
1018 return this;
1019 }
1020 int[] values = getValues(); // cloned
1021 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, years);
1022 return new Period(values, getPeriodType());
1023 }
1024
1025 /**
1026 * Returns a new period plus the specified number of months added.
1027 * <p>
1028 * This period instance is immutable and unaffected by this method call.
1029 *
1030 * @param months the amount of months to add, may be negative
1031 * @return the new period plus the increased months
1032 * @throws UnsupportedOperationException if the field is not supported
1033 */
1034 public Period plusMonths(int months) {
1035 if (months == 0) {
1036 return this;
1037 }
1038 int[] values = getValues(); // cloned
1039 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, months);
1040 return new Period(values, getPeriodType());
1041 }
1042
1043 /**
1044 * Returns a new period plus the specified number of weeks added.
1045 * <p>
1046 * This period instance is immutable and unaffected by this method call.
1047 *
1048 * @param weeks the amount of weeks to add, may be negative
1049 * @return the new period plus the increased weeks
1050 * @throws UnsupportedOperationException if the field is not supported
1051 */
1052 public Period plusWeeks(int weeks) {
1053 if (weeks == 0) {
1054 return this;
1055 }
1056 int[] values = getValues(); // cloned
1057 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, weeks);
1058 return new Period(values, getPeriodType());
1059 }
1060
1061 /**
1062 * Returns a new period plus the specified number of days added.
1063 * <p>
1064 * This period instance is immutable and unaffected by this method call.
1065 *
1066 * @param days the amount of days to add, may be negative
1067 * @return the new period plus the increased days
1068 * @throws UnsupportedOperationException if the field is not supported
1069 */
1070 public Period plusDays(int days) {
1071 if (days == 0) {
1072 return this;
1073 }
1074 int[] values = getValues(); // cloned
1075 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, days);
1076 return new Period(values, getPeriodType());
1077 }
1078
1079 /**
1080 * Returns a new period plus the specified number of hours added.
1081 * <p>
1082 * This period instance is immutable and unaffected by this method call.
1083 *
1084 * @param hours the amount of hours to add, may be negative
1085 * @return the new period plus the increased hours
1086 * @throws UnsupportedOperationException if the field is not supported
1087 */
1088 public Period plusHours(int hours) {
1089 if (hours == 0) {
1090 return this;
1091 }
1092 int[] values = getValues(); // cloned
1093 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, hours);
1094 return new Period(values, getPeriodType());
1095 }
1096
1097 /**
1098 * Returns a new period plus the specified number of minutes added.
1099 * <p>
1100 * This period instance is immutable and unaffected by this method call.
1101 *
1102 * @param minutes the amount of minutes to add, may be negative
1103 * @return the new period plus the increased minutes
1104 * @throws UnsupportedOperationException if the field is not supported
1105 */
1106 public Period plusMinutes(int minutes) {
1107 if (minutes == 0) {
1108 return this;
1109 }
1110 int[] values = getValues(); // cloned
1111 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes);
1112 return new Period(values, getPeriodType());
1113 }
1114
1115 /**
1116 * Returns a new period plus the specified number of seconds added.
1117 * <p>
1118 * This period instance is immutable and unaffected by this method call.
1119 *
1120 * @param seconds the amount of seconds to add, may be negative
1121 * @return the new period plus the increased seconds
1122 * @throws UnsupportedOperationException if the field is not supported
1123 */
1124 public Period plusSeconds(int seconds) {
1125 if (seconds == 0) {
1126 return this;
1127 }
1128 int[] values = getValues(); // cloned
1129 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, seconds);
1130 return new Period(values, getPeriodType());
1131 }
1132
1133 /**
1134 * Returns a new period plus the specified number of millis added.
1135 * <p>
1136 * This period instance is immutable and unaffected by this method call.
1137 *
1138 * @param millis the amount of millis to add, may be negative
1139 * @return the new period plus the increased millis
1140 * @throws UnsupportedOperationException if the field is not supported
1141 */
1142 public Period plusMillis(int millis) {
1143 if (millis == 0) {
1144 return this;
1145 }
1146 int[] values = getValues(); // cloned
1147 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, millis);
1148 return new Period(values, getPeriodType());
1149 }
1150
1151 //-----------------------------------------------------------------------
1152 /**
1153 * Returns a new period with the specified period subtracted.
1154 * <p>
1155 * Each field of the period is subtracted separately. Thus a period of
1156 * 3 hours 30 minutes minus 2 hours 40 minutes will produce a result
1157 * of 1 hour and -10 minutes - see {@link #normalizedStandard()}.
1158 * <p>
1159 * If the period being added contains a non-zero amount for a field that
1160 * is not supported in this period then an exception is thrown.
1161 * <p>
1162 * This period instance is immutable and unaffected by this method call.
1163 *
1164 * @param period the period to add, null adds zero and returns this
1165 * @return the new updated period
1166 * @throws UnsupportedOperationException if any field is not supported
1167 * @since 1.5
1168 */
1169 public Period minus(ReadablePeriod period) {
1170 if (period == null) {
1171 return this;
1172 }
1173 int[] values = getValues(); // cloned
1174 getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, -period.get(DurationFieldType.YEARS_TYPE));
1175 getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, -period.get(DurationFieldType.MONTHS_TYPE));
1176 getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, -period.get(DurationFieldType.WEEKS_TYPE));
1177 getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, -period.get(DurationFieldType.DAYS_TYPE));
1178 getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, -period.get(DurationFieldType.HOURS_TYPE));
1179 getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, -period.get(DurationFieldType.MINUTES_TYPE));
1180 getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, -period.get(DurationFieldType.SECONDS_TYPE));
1181 getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, -period.get(DurationFieldType.MILLIS_TYPE));
1182 return new Period(values, getPeriodType());
1183 }
1184
1185 //-----------------------------------------------------------------------
1186 /**
1187 * Returns a new period with the specified number of years taken away.
1188 * <p>
1189 * This period instance is immutable and unaffected by this method call.
1190 *
1191 * @param years the amount of years to take away, may be negative
1192 * @return the new period with the increased years
1193 * @throws UnsupportedOperationException if the field is not supported
1194 */
1195 public Period minusYears(int years) {
1196 return plusYears(-years);
1197 }
1198
1199 /**
1200 * Returns a new period minus the specified number of months taken away.
1201 * <p>
1202 * This period instance is immutable and unaffected by this method call.
1203 *
1204 * @param months the amount of months to take away, may be negative
1205 * @return the new period minus the increased months
1206 * @throws UnsupportedOperationException if the field is not supported
1207 */
1208 public Period minusMonths(int months) {
1209 return plusMonths(-months);
1210 }
1211
1212 /**
1213 * Returns a new period minus the specified number of weeks taken away.
1214 * <p>
1215 * This period instance is immutable and unaffected by this method call.
1216 *
1217 * @param weeks the amount of weeks to take away, may be negative
1218 * @return the new period minus the increased weeks
1219 * @throws UnsupportedOperationException if the field is not supported
1220 */
1221 public Period minusWeeks(int weeks) {
1222 return plusWeeks(-weeks);
1223 }
1224
1225 /**
1226 * Returns a new period minus the specified number of days taken away.
1227 * <p>
1228 * This period instance is immutable and unaffected by this method call.
1229 *
1230 * @param days the amount of days to take away, may be negative
1231 * @return the new period minus the increased days
1232 * @throws UnsupportedOperationException if the field is not supported
1233 */
1234 public Period minusDays(int days) {
1235 return plusDays(-days);
1236 }
1237
1238 /**
1239 * Returns a new period minus the specified number of hours taken away.
1240 * <p>
1241 * This period instance is immutable and unaffected by this method call.
1242 *
1243 * @param hours the amount of hours to take away, may be negative
1244 * @return the new period minus the increased hours
1245 * @throws UnsupportedOperationException if the field is not supported
1246 */
1247 public Period minusHours(int hours) {
1248 return plusHours(-hours);
1249 }
1250
1251 /**
1252 * Returns a new period minus the specified number of minutes taken away.
1253 * <p>
1254 * This period instance is immutable and unaffected by this method call.
1255 *
1256 * @param minutes the amount of minutes to take away, may be negative
1257 * @return the new period minus the increased minutes
1258 * @throws UnsupportedOperationException if the field is not supported
1259 */
1260 public Period minusMinutes(int minutes) {
1261 return plusMinutes(-minutes);
1262 }
1263
1264 /**
1265 * Returns a new period minus the specified number of seconds taken away.
1266 * <p>
1267 * This period instance is immutable and unaffected by this method call.
1268 *
1269 * @param seconds the amount of seconds to take away, may be negative
1270 * @return the new period minus the increased seconds
1271 * @throws UnsupportedOperationException if the field is not supported
1272 */
1273 public Period minusSeconds(int seconds) {
1274 return plusSeconds(-seconds);
1275 }
1276
1277 /**
1278 * Returns a new period minus the specified number of millis taken away.
1279 * <p>
1280 * This period instance is immutable and unaffected by this method call.
1281 *
1282 * @param millis the amount of millis to take away, may be negative
1283 * @return the new period minus the increased millis
1284 * @throws UnsupportedOperationException if the field is not supported
1285 */
1286 public Period minusMillis(int millis) {
1287 return plusMillis(-millis);
1288 }
1289
1290 //-----------------------------------------------------------------------
1291 /**
1292 * Returns a new instance with each element in this period multiplied
1293 * by the specified scalar.
1294 *
1295 * @param scalar the scalar to multiply by, not null
1296 * @return a {@code Period} based on this period with the amounts multiplied by the scalar, never null
1297 * @throws ArithmeticException if the capacity of any field is exceeded
1298 * @since 2.1
1299 */
1300 public Period multipliedBy(int scalar) {
1301 if (this == ZERO || scalar == 1) {
1302 return this;
1303 }
1304 int[] values = getValues(); // cloned
1305 for (int i = 0; i < values.length; i++) {
1306 values[i] = FieldUtils.safeMultiply(values[i], scalar);
1307 }
1308 return new Period(values, getPeriodType());
1309 }
1310
1311 /**
1312 * Returns a new instance with each amount in this period negated.
1313 *
1314 * @return a {@code Period} based on this period with the amounts negated, never null
1315 * @throws ArithmeticException if any field has the minimum value
1316 * @since 2.1
1317 */
1318 public Period negated() {
1319 return multipliedBy(-1);
1320 }
1321
1322 //-----------------------------------------------------------------------
1323 /**
1324 * Converts this period to a period in weeks assuming a
1325 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1326 * <p>
1327 * This method allows you to convert between different types of period.
1328 * However to achieve this it makes the assumption that all
1329 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1330 * all minutes are 60 seconds. This is not true when daylight savings time
1331 * is considered, and may also not be true for some unusual chronologies.
1332 * However, it is included as it is a useful operation for many
1333 * applications and business rules.
1334 * <p>
1335 * If the period contains years or months, an exception will be thrown.
1336 *
1337 * @return a period representing the number of standard weeks in this period
1338 * @throws UnsupportedOperationException if the period contains years or months
1339 * @throws ArithmeticException if the number of weeks is too large to be represented
1340 * @since 1.5
1341 */
1342 public Weeks toStandardWeeks() {
1343 checkYearsAndMonths("Weeks");
1344 long millis = getMillis(); // assign to a long
1345 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND;
1346 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE;
1347 millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR;
1348 millis += ((long) getDays()) * DateTimeConstants.MILLIS_PER_DAY;
1349 long weeks = ((long) getWeeks()) + millis / DateTimeConstants.MILLIS_PER_WEEK;
1350 return Weeks.weeks(FieldUtils.safeToInt(weeks));
1351 }
1352
1353 /**
1354 * Converts this period to a period in days assuming a
1355 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1356 * <p>
1357 * This method allows you to convert between different types of period.
1358 * However to achieve this it makes the assumption that all
1359 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1360 * all minutes are 60 seconds. This is not true when daylight savings time
1361 * is considered, and may also not be true for some unusual chronologies.
1362 * However, it is included as it is a useful operation for many
1363 * applications and business rules.
1364 * <p>
1365 * If the period contains years or months, an exception will be thrown.
1366 *
1367 * @return a period representing the number of standard days in this period
1368 * @throws UnsupportedOperationException if the period contains years or months
1369 * @throws ArithmeticException if the number of days is too large to be represented
1370 * @since 1.5
1371 */
1372 public Days toStandardDays() {
1373 checkYearsAndMonths("Days");
1374 long millis = getMillis(); // assign to a long
1375 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND;
1376 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE;
1377 millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR;
1378 long days = millis / DateTimeConstants.MILLIS_PER_DAY;
1379 days = FieldUtils.safeAdd(days, getDays());
1380 days = FieldUtils.safeAdd(days, ((long) getWeeks()) * ((long) DateTimeConstants.DAYS_PER_WEEK));
1381 return Days.days(FieldUtils.safeToInt(days));
1382 }
1383
1384 /**
1385 * Converts this period to a period in hours assuming a
1386 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1387 * <p>
1388 * This method allows you to convert between different types of period.
1389 * However to achieve this it makes the assumption that all
1390 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1391 * all minutes are 60 seconds. This is not true when daylight savings time
1392 * is considered, and may also not be true for some unusual chronologies.
1393 * However, it is included as it is a useful operation for many
1394 * applications and business rules.
1395 * <p>
1396 * If the period contains years or months, an exception will be thrown.
1397 *
1398 * @return a period representing the number of standard hours in this period
1399 * @throws UnsupportedOperationException if the period contains years or months
1400 * @throws ArithmeticException if the number of hours is too large to be represented
1401 * @since 1.5
1402 */
1403 public Hours toStandardHours() {
1404 checkYearsAndMonths("Hours");
1405 long millis = getMillis(); // assign to a long
1406 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND;
1407 millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE;
1408 long hours = millis / DateTimeConstants.MILLIS_PER_HOUR;
1409 hours = FieldUtils.safeAdd(hours, getHours());
1410 hours = FieldUtils.safeAdd(hours, ((long) getDays()) * ((long) DateTimeConstants.HOURS_PER_DAY));
1411 hours = FieldUtils.safeAdd(hours, ((long) getWeeks()) * ((long) DateTimeConstants.HOURS_PER_WEEK));
1412 return Hours.hours(FieldUtils.safeToInt(hours));
1413 }
1414
1415 /**
1416 * Converts this period to a period in minutes assuming a
1417 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1418 * <p>
1419 * This method allows you to convert between different types of period.
1420 * However to achieve this it makes the assumption that all
1421 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1422 * all minutes are 60 seconds. This is not true when daylight savings time
1423 * is considered, and may also not be true for some unusual chronologies.
1424 * However, it is included as it is a useful operation for many
1425 * applications and business rules.
1426 * <p>
1427 * If the period contains years or months, an exception will be thrown.
1428 *
1429 * @return a period representing the number of standard minutes in this period
1430 * @throws UnsupportedOperationException if the period contains years or months
1431 * @throws ArithmeticException if the number of minutes is too large to be represented
1432 * @since 1.5
1433 */
1434 public Minutes toStandardMinutes() {
1435 checkYearsAndMonths("Minutes");
1436 long millis = getMillis(); // assign to a long
1437 millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND;
1438 long minutes = millis / DateTimeConstants.MILLIS_PER_MINUTE;
1439 minutes = FieldUtils.safeAdd(minutes, getMinutes());
1440 minutes = FieldUtils.safeAdd(minutes, ((long) getHours()) * ((long) DateTimeConstants.MINUTES_PER_HOUR));
1441 minutes = FieldUtils.safeAdd(minutes, ((long) getDays()) * ((long) DateTimeConstants.MINUTES_PER_DAY));
1442 minutes = FieldUtils.safeAdd(minutes, ((long) getWeeks()) * ((long) DateTimeConstants.MINUTES_PER_WEEK));
1443 return Minutes.minutes(FieldUtils.safeToInt(minutes));
1444 }
1445
1446 /**
1447 * Converts this period to a period in seconds assuming a
1448 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1449 * <p>
1450 * This method allows you to convert between different types of period.
1451 * However to achieve this it makes the assumption that all
1452 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1453 * all minutes are 60 seconds. This is not true when daylight savings time
1454 * is considered, and may also not be true for some unusual chronologies.
1455 * However, it is included as it is a useful operation for many
1456 * applications and business rules.
1457 * <p>
1458 * If the period contains years or months, an exception will be thrown.
1459 *
1460 * @return a period representing the number of standard seconds in this period
1461 * @throws UnsupportedOperationException if the period contains years or months
1462 * @throws ArithmeticException if the number of seconds is too large to be represented
1463 * @since 1.5
1464 */
1465 public Seconds toStandardSeconds() {
1466 checkYearsAndMonths("Seconds");
1467 long seconds = getMillis() / DateTimeConstants.MILLIS_PER_SECOND;
1468 seconds = FieldUtils.safeAdd(seconds, getSeconds());
1469 seconds = FieldUtils.safeAdd(seconds, ((long) getMinutes()) * ((long) DateTimeConstants.SECONDS_PER_MINUTE));
1470 seconds = FieldUtils.safeAdd(seconds, ((long) getHours()) * ((long) DateTimeConstants.SECONDS_PER_HOUR));
1471 seconds = FieldUtils.safeAdd(seconds, ((long) getDays()) * ((long) DateTimeConstants.SECONDS_PER_DAY));
1472 seconds = FieldUtils.safeAdd(seconds, ((long) getWeeks()) * ((long) DateTimeConstants.SECONDS_PER_WEEK));
1473 return Seconds.seconds(FieldUtils.safeToInt(seconds));
1474 }
1475
1476 //-----------------------------------------------------------------------
1477 /**
1478 * Converts this period to a duration assuming a
1479 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1480 * <p>
1481 * This method allows you to convert from a period to a duration.
1482 * However to achieve this it makes the assumption that all
1483 * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1484 * all minutes are 60 seconds. This is not true when daylight savings time
1485 * is considered, and may also not be true for some unusual chronologies.
1486 * However, it is included as it is a useful operation for many
1487 * applications and business rules.
1488 * <p>
1489 * If the period contains years or months, an exception will be thrown.
1490 *
1491 * @return a duration equivalent to this period
1492 * @throws UnsupportedOperationException if the period contains years or months
1493 * @since 1.5
1494 */
1495 public Duration toStandardDuration() {
1496 checkYearsAndMonths("Duration");
1497 long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs
1498 millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
1499 millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
1500 millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
1501 millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY));
1502 millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
1503 return new Duration(millis);
1504 }
1505
1506 /**
1507 * Check that there are no years or months in the period.
1508 *
1509 * @param destintionType the destination type, not null
1510 * @throws UnsupportedOperationException if the period contains years or months
1511 */
1512 private void checkYearsAndMonths(String destintionType) {
1513 if (getMonths() != 0) {
1514 throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains months and months vary in length");
1515 }
1516 if (getYears() != 0) {
1517 throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains years and years vary in length");
1518 }
1519 }
1520
1521 //-----------------------------------------------------------------------
1522 /**
1523 * Normalizes this period using standard rules, assuming a 12 month year,
1524 * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1525 * <p>
1526 * This method allows you to normalize a period.
1527 * However to achieve this it makes the assumption that all years are
1528 * 12 months, all weeks are 7 days, all days are 24 hours,
1529 * all hours are 60 minutes and all minutes are 60 seconds. This is not
1530 * true when daylight savings time is considered, and may also not be true
1531 * for some chronologies. However, it is included as it is a useful operation
1532 * for many applications and business rules.
1533 * <p>
1534 * If the period contains years or months, then the months will be
1535 * normalized to be between 0 and 11. The days field and below will be
1536 * normalized as necessary, however this will not overflow into the months
1537 * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months.
1538 * But a period of 1 month 40 days will remain as 1 month 40 days.
1539 * <p>
1540 * The result will always have a <code>PeriodType</code> of standard, thus
1541 * days will be grouped into weeks.
1542 *
1543 * @return a normalized period equivalent to this period
1544 * @throws ArithmeticException if any field is too large to be represented
1545 * @since 1.5
1546 */
1547 public Period normalizedStandard() {
1548 return normalizedStandard(PeriodType.standard());
1549 }
1550
1551 //-----------------------------------------------------------------------
1552 /**
1553 * Normalizes this period using standard rules, assuming a 12 month year,
1554 * 7 day week, 24 hour day, 60 minute hour and 60 second minute,
1555 * providing control over how the result is split into fields.
1556 * <p>
1557 * This method allows you to normalize a period.
1558 * However to achieve this it makes the assumption that all years are
1559 * 12 months, all weeks are 7 days, all days are 24 hours,
1560 * all hours are 60 minutes and all minutes are 60 seconds. This is not
1561 * true when daylight savings time is considered, and may also not be true
1562 * for some chronologies. However, it is included as it is a useful operation
1563 * for many applications and business rules.
1564 * <p>
1565 * If the period contains years or months, then the months will be
1566 * normalized to be between 0 and 11. The days field and below will be
1567 * normalized as necessary, however this will not overflow into the months
1568 * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months.
1569 * But a period of 1 month 40 days will remain as 1 month 40 days.
1570 * <p>
1571 * The PeriodType parameter controls how the result is created. It allows
1572 * you to omit certain fields from the result if desired. For example,
1573 * you may not want the result to include weeks, in which case you pass
1574 * in <code>PeriodType.yearMonthDayTime()</code>.
1575 *
1576 * @param type the period type of the new period, null means standard type
1577 * @return a normalized period equivalent to this period
1578 * @throws ArithmeticException if any field is too large to be represented
1579 * @throws UnsupportedOperationException if this period contains non-zero
1580 * years or months but the specified period type does not support them
1581 * @since 1.5
1582 */
1583 public Period normalizedStandard(PeriodType type) {
1584 long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs
1585 millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
1586 millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
1587 millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
1588 millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY));
1589 millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
1590 Period result = new Period(millis, DateTimeUtils.getPeriodType(type), ISOChronology.getInstanceUTC());
1591 int years = getYears();
1592 int months = getMonths();
1593 if (years != 0 || months != 0) {
1594 years = FieldUtils.safeAdd(years, months / 12);
1595 months = months % 12;
1596 if (years != 0) {
1597 result = result.withYears(years);
1598 }
1599 if (months != 0) {
1600 result = result.withMonths(months);
1601 }
1602 }
1603 return result;
1604 }
1605
1606 }