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    }