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