0001: /*
0002: * Copyright 2001-2006 Stephen Colebourne
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: package org.joda.time;
0017:
0018: import java.io.Serializable;
0019:
0020: import org.joda.time.base.BasePeriod;
0021: import org.joda.time.chrono.ISOChronology;
0022: import org.joda.time.field.FieldUtils;
0023: import org.joda.time.format.ISOPeriodFormat;
0024:
0025: /**
0026: * An immutable time period specifying a set of duration field values.
0027: * <p>
0028: * A time period is divided into a number of fields, such as hours and seconds.
0029: * Which fields are supported is defined by the PeriodType class.
0030: * The default is the standard period type, which supports years, months, weeks, days,
0031: * hours, minutes, seconds and millis.
0032: * <p>
0033: * When this time period is added to an instant, the effect is of adding each field in turn.
0034: * As a result, this takes into account daylight savings time.
0035: * Adding a time period of 1 day to the day before daylight savings starts will only add
0036: * 23 hours rather than 24 to ensure that the time remains the same.
0037: * If this is not the behaviour you want, then see {@link Duration}.
0038: * <p>
0039: * The definition of a period also affects the equals method. A period of 1
0040: * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes.
0041: * This is because periods represent an abstracted definition of a time period
0042: * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight
0043: * savings boundary). To compare the actual duration of two periods, convert
0044: * both to durations using toDuration, an operation that emphasises that the
0045: * result may differ according to the date you choose.
0046: * <p>
0047: * Period is thread-safe and immutable, provided that the PeriodType is as well.
0048: * All standard PeriodType classes supplied are thread-safe and immutable.
0049: *
0050: * @author Brian S O'Neill
0051: * @author Stephen Colebourne
0052: * @since 1.0
0053: * @see MutablePeriod
0054: */
0055: public final class Period extends BasePeriod implements ReadablePeriod,
0056: Serializable {
0057:
0058: /**
0059: * A period of zero length and standard period type.
0060: * @since 1.4
0061: */
0062: public static final Period ZERO = new Period();
0063:
0064: /** Serialization version */
0065: private static final long serialVersionUID = 741052353876488155L;
0066:
0067: //-----------------------------------------------------------------------
0068: /**
0069: * Create a period with a specified number of years.
0070: * <p>
0071: * The standard period type is used, thus you can add other fields such
0072: * as months or days using the <code>withXxx()</code> methods.
0073: * For example, <code>Period.years(2).withMonths(6);</code>
0074: * <p>
0075: * If you want a year-based period that cannot have other fields added,
0076: * then you should consider using {@link Years}.
0077: *
0078: * @param years the amount of years in this period
0079: * @return the period
0080: */
0081: public static Period years(int years) {
0082: return new Period(new int[] { years, 0, 0, 0, 0, 0, 0, 0, 0 },
0083: PeriodType.standard());
0084: }
0085:
0086: /**
0087: * Create a period with a specified number of months.
0088: * <p>
0089: * The standard period type is used, thus you can add other fields such
0090: * as years or days using the <code>withXxx()</code> methods.
0091: * For example, <code>Period.months(2).withDays(6);</code>
0092: * <p>
0093: * If you want a month-based period that cannot have other fields added,
0094: * then you should consider using {@link Months}.
0095: *
0096: * @param months the amount of months in this period
0097: * @return the period
0098: */
0099: public static Period months(int months) {
0100: return new Period(new int[] { 0, months, 0, 0, 0, 0, 0, 0 },
0101: PeriodType.standard());
0102: }
0103:
0104: /**
0105: * Create a period with a specified number of weeks.
0106: * <p>
0107: * The standard period type is used, thus you can add other fields such
0108: * as months or days using the <code>withXxx()</code> methods.
0109: * For example, <code>Period.weeks(2).withDays(6);</code>
0110: * <p>
0111: * If you want a week-based period that cannot have other fields added,
0112: * then you should consider using {@link Weeks}.
0113: *
0114: * @param weeks the amount of weeks in this period
0115: * @return the period
0116: */
0117: public static Period weeks(int weeks) {
0118: return new Period(new int[] { 0, 0, weeks, 0, 0, 0, 0, 0 },
0119: PeriodType.standard());
0120: }
0121:
0122: /**
0123: * Create a period with a specified number of days.
0124: * <p>
0125: * The standard period type is used, thus you can add other fields such
0126: * as months or weeks using the <code>withXxx()</code> methods.
0127: * For example, <code>Period.days(2).withHours(6);</code>
0128: * <p>
0129: * If you want a day-based period that cannot have other fields added,
0130: * then you should consider using {@link Days}.
0131: *
0132: * @param days the amount of days in this period
0133: * @return the period
0134: */
0135: public static Period days(int days) {
0136: return new Period(new int[] { 0, 0, 0, days, 0, 0, 0, 0 },
0137: PeriodType.standard());
0138: }
0139:
0140: /**
0141: * Create a period with a specified number of hours.
0142: * <p>
0143: * The standard period type is used, thus you can add other fields such
0144: * as months or days using the <code>withXxx()</code> methods.
0145: * For example, <code>Period.hours(2).withMinutes(30);</code>
0146: * <p>
0147: * If you want a hour-based period that cannot have other fields added,
0148: * then you should consider using {@link Hours}.
0149: *
0150: * @param hours the amount of hours in this period
0151: * @return the period
0152: */
0153: public static Period hours(int hours) {
0154: return new Period(new int[] { 0, 0, 0, 0, hours, 0, 0, 0 },
0155: PeriodType.standard());
0156: }
0157:
0158: /**
0159: * Create a period with a specified number of minutes.
0160: * <p>
0161: * The standard period type is used, thus you can add other fields such
0162: * as days or hours using the <code>withXxx()</code> methods.
0163: * For example, <code>Period.minutes(2).withSeconds(30);</code>
0164: * <p>
0165: * If you want a minute-based period that cannot have other fields added,
0166: * then you should consider using {@link Minutes}.
0167: *
0168: * @param minutes the amount of minutes in this period
0169: * @return the period
0170: */
0171: public static Period minutes(int minutes) {
0172: return new Period(new int[] { 0, 0, 0, 0, 0, minutes, 0, 0 },
0173: PeriodType.standard());
0174: }
0175:
0176: /**
0177: * Create a period with a specified number of seconds.
0178: * <p>
0179: * The standard period type is used, thus you can add other fields such
0180: * as days or hours using the <code>withXxx()</code> methods.
0181: * For example, <code>Period.seconds(2).withMillis(30);</code>
0182: * <p>
0183: * If you want a second-based period that cannot have other fields added,
0184: * then you should consider using {@link Seconds}.
0185: *
0186: * @param seconds the amount of seconds in this period
0187: * @return the period
0188: */
0189: public static Period seconds(int seconds) {
0190: return new Period(new int[] { 0, 0, 0, 0, 0, 0, seconds, 0 },
0191: PeriodType.standard());
0192: }
0193:
0194: /**
0195: * Create a period with a specified number of millis.
0196: * <p>
0197: * The standard period type is used, thus you can add other fields such
0198: * as days or hours using the <code>withXxx()</code> methods.
0199: * For example, <code>Period.millis(20).withSeconds(30);</code>
0200: *
0201: * @param millis the amount of millis in this period
0202: * @return the period
0203: */
0204: public static Period millis(int millis) {
0205: return new Period(new int[] { 0, 0, 0, 0, 0, 0, 0, millis },
0206: PeriodType.standard());
0207: }
0208:
0209: //-----------------------------------------------------------------------
0210: /**
0211: * Creates a period from two partially specified times, calculating
0212: * by field difference.
0213: * <p>
0214: * The two partials must contain the same fields, thus you can specify
0215: * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
0216: * but not one of each. Also, the partial may not contain overlapping
0217: * fields, such as dayOfWeek and dayOfMonth.
0218: * <p>
0219: * Calculation by field difference works by extracting the difference
0220: * one field at a time and not wrapping into other fields.
0221: * Thus 2005-06-09/2007-04-12 will yield P1Y-2M3D.
0222: * <p>
0223: * For example, you have an event that always runs from the 27th of
0224: * each month to the 2nd of the next month. If you calculate this
0225: * period using a standard constructor, then you will get between
0226: * P3D and P6D depending on the month. If you use this method, then
0227: * you will get P1M-25D. This field-difference based period can
0228: * be successfully applied to each month of the year to obtain the
0229: * correct end date for a given start date.
0230: *
0231: * @param start the start of the period, must not be null
0232: * @param end the end of the period, must not be null
0233: * @throws IllegalArgumentException if the partials are null or invalid
0234: * @since 1.1
0235: */
0236: public static Period fieldDifference(ReadablePartial start,
0237: ReadablePartial end) {
0238: if (start == null || end == null) {
0239: throw new IllegalArgumentException(
0240: "ReadablePartial objects must not be null");
0241: }
0242: if (start.size() != end.size()) {
0243: throw new IllegalArgumentException(
0244: "ReadablePartial objects must have the same set of fields");
0245: }
0246: DurationFieldType[] types = new DurationFieldType[start.size()];
0247: int[] values = new int[start.size()];
0248: for (int i = 0, isize = start.size(); i < isize; i++) {
0249: if (start.getFieldType(i) != end.getFieldType(i)) {
0250: throw new IllegalArgumentException(
0251: "ReadablePartial objects must have the same set of fields");
0252: }
0253: types[i] = start.getFieldType(i).getDurationType();
0254: if (i > 0 && types[i - 1] == types[i]) {
0255: throw new IllegalArgumentException(
0256: "ReadablePartial objects must not have overlapping fields");
0257: }
0258: values[i] = end.getValue(i) - start.getValue(i);
0259: }
0260: return new Period(values, PeriodType.forFields(types));
0261: }
0262:
0263: //-----------------------------------------------------------------------
0264: /**
0265: * Creates a new empty period with the standard set of fields.
0266: * <p>
0267: * One way to initialise a period is as follows:
0268: * <pre>
0269: * Period = new Period().withYears(6).withMonths(3).withSeconds(23);
0270: * </pre>
0271: * Bear in mind that this creates four period instances in total, three of
0272: * which are immediately discarded.
0273: * The alterative is more efficient, but less readable:
0274: * <pre>
0275: * Period = new Period(6, 3, 0, 0, 0, 0, 23, 0);
0276: * </pre>
0277: * The following is also slightly less wasteful:
0278: * <pre>
0279: * Period = Period.years(6).withMonths(3).withSeconds(23);
0280: * </pre>
0281: */
0282: public Period() {
0283: super (0L, null, null);
0284: }
0285:
0286: /**
0287: * Create a period from a set of field values using the standard set of fields.
0288: * Note that the parameters specify the time fields hours, minutes,
0289: * seconds and millis, not the date fields.
0290: *
0291: * @param hours amount of hours in this period
0292: * @param minutes amount of minutes in this period
0293: * @param seconds amount of seconds in this period
0294: * @param millis amount of milliseconds in this period
0295: */
0296: public Period(int hours, int minutes, int seconds, int millis) {
0297: super (0, 0, 0, 0, hours, minutes, seconds, millis, PeriodType
0298: .standard());
0299: }
0300:
0301: /**
0302: * Create a period from a set of field values using the standard set of fields.
0303: *
0304: * @param years amount of years in this period
0305: * @param months amount of months in this period
0306: * @param weeks amount of weeks in this period
0307: * @param days amount of days in this period
0308: * @param hours amount of hours in this period
0309: * @param minutes amount of minutes in this period
0310: * @param seconds amount of seconds in this period
0311: * @param millis amount of milliseconds in this period
0312: */
0313: public Period(int years, int months, int weeks, int days,
0314: int hours, int minutes, int seconds, int millis) {
0315: super (years, months, weeks, days, hours, minutes, seconds,
0316: millis, PeriodType.standard());
0317: }
0318:
0319: /**
0320: * Create a period from a set of field values.
0321: * <p>
0322: * There is usually little need to use this constructor.
0323: * The period type is used primarily to define how to split an interval into a period.
0324: * As this constructor already is split, the period type does no real work.
0325: *
0326: * @param years amount of years in this period, which must be zero if unsupported
0327: * @param months amount of months in this period, which must be zero if unsupported
0328: * @param weeks amount of weeks in this period, which must be zero if unsupported
0329: * @param days amount of days in this period, which must be zero if unsupported
0330: * @param hours amount of hours in this period, which must be zero if unsupported
0331: * @param minutes amount of minutes in this period, which must be zero if unsupported
0332: * @param seconds amount of seconds in this period, which must be zero if unsupported
0333: * @param millis amount of milliseconds in this period, which must be zero if unsupported
0334: * @param type which set of fields this period supports, null means AllType
0335: * @throws IllegalArgumentException if an unsupported field's value is non-zero
0336: */
0337: public Period(int years, int months, int weeks, int days,
0338: int hours, int minutes, int seconds, int millis,
0339: PeriodType type) {
0340: super (years, months, weeks, days, hours, minutes, seconds,
0341: millis, type);
0342: }
0343:
0344: /**
0345: * Creates a period from the given millisecond duration using the standard
0346: * set of fields.
0347: * <p>
0348: * Only precise fields in the period type will be used.
0349: * For the standard period type this is the time fields only.
0350: * Thus the year, month, week and day fields will not be populated.
0351: * <p>
0352: * If the duration is small, less than one day, then this method will perform
0353: * as you might expect and split the fields evenly.
0354: * <p>
0355: * If the duration is larger than one day then all the remaining duration will
0356: * be stored in the largest available precise field, hours in this case.
0357: * <p>
0358: * For example, a duration equal to (365 + 60 + 5) days will be converted to
0359: * ((365 + 60 + 5) * 24) hours by this constructor.
0360: * <p>
0361: * For more control over the conversion process, you have two options:
0362: * <ul>
0363: * <li>convert the duration to an {@link Interval}, and from there obtain the period
0364: * <li>specify a period type that contains precise definitions of the day and larger
0365: * fields, such as UTC
0366: * </ul>
0367: *
0368: * @param duration the duration, in milliseconds
0369: */
0370: public Period(long duration) {
0371: super (duration, null, null);
0372: }
0373:
0374: /**
0375: * Creates a period from the given millisecond duration.
0376: * <p>
0377: * Only precise fields in the period type will be used.
0378: * Imprecise fields will not be populated.
0379: * <p>
0380: * If the duration is small then this method will perform
0381: * as you might expect and split the fields evenly.
0382: * <p>
0383: * If the duration is large then all the remaining duration will
0384: * be stored in the largest available precise field.
0385: * For details as to which fields are precise, review the period type javadoc.
0386: *
0387: * @param duration the duration, in milliseconds
0388: * @param type which set of fields this period supports, null means standard
0389: */
0390: public Period(long duration, PeriodType type) {
0391: super (duration, type, null);
0392: }
0393:
0394: /**
0395: * Creates a period from the given millisecond duration using the standard
0396: * set of fields.
0397: * <p>
0398: * Only precise fields in the period type will be used.
0399: * Imprecise fields will not be populated.
0400: * <p>
0401: * If the duration is small then this method will perform
0402: * as you might expect and split the fields evenly.
0403: * <p>
0404: * If the duration is large then all the remaining duration will
0405: * be stored in the largest available precise field.
0406: * For details as to which fields are precise, review the period type javadoc.
0407: *
0408: * @param duration the duration, in milliseconds
0409: * @param chronology the chronology to use to split the duration, null means ISO default
0410: */
0411: public Period(long duration, Chronology chronology) {
0412: super (duration, null, chronology);
0413: }
0414:
0415: /**
0416: * Creates a period from the given millisecond duration.
0417: * <p>
0418: * Only precise fields in the period type will be used.
0419: * Imprecise fields will not be populated.
0420: * <p>
0421: * If the duration is small then this method will perform
0422: * as you might expect and split the fields evenly.
0423: * <p>
0424: * If the duration is large then all the remaining duration will
0425: * be stored in the largest available precise field.
0426: * For details as to which fields are precise, review the period type javadoc.
0427: *
0428: * @param duration the duration, in milliseconds
0429: * @param type which set of fields this period supports, null means standard
0430: * @param chronology the chronology to use to split the duration, null means ISO default
0431: */
0432: public Period(long duration, PeriodType type, Chronology chronology) {
0433: super (duration, type, chronology);
0434: }
0435:
0436: /**
0437: * Creates a period from the given interval endpoints using the standard
0438: * set of fields.
0439: *
0440: * @param startInstant interval start, in milliseconds
0441: * @param endInstant interval end, in milliseconds
0442: */
0443: public Period(long startInstant, long endInstant) {
0444: super (startInstant, endInstant, null, null);
0445: }
0446:
0447: /**
0448: * Creates a period from the given interval endpoints.
0449: *
0450: * @param startInstant interval start, in milliseconds
0451: * @param endInstant interval end, in milliseconds
0452: * @param type which set of fields this period supports, null means standard
0453: */
0454: public Period(long startInstant, long endInstant, PeriodType type) {
0455: super (startInstant, endInstant, type, null);
0456: }
0457:
0458: /**
0459: * Creates a period from the given interval endpoints using the standard
0460: * set of fields.
0461: *
0462: * @param startInstant interval start, in milliseconds
0463: * @param endInstant interval end, in milliseconds
0464: * @param chrono the chronology to use, null means ISO in default zone
0465: */
0466: public Period(long startInstant, long endInstant, Chronology chrono) {
0467: super (startInstant, endInstant, null, chrono);
0468: }
0469:
0470: /**
0471: * Creates a period from the given interval endpoints.
0472: *
0473: * @param startInstant interval start, in milliseconds
0474: * @param endInstant interval end, in milliseconds
0475: * @param type which set of fields this period supports, null means standard
0476: * @param chrono the chronology to use, null means ISO in default zone
0477: */
0478: public Period(long startInstant, long endInstant, PeriodType type,
0479: Chronology chrono) {
0480: super (startInstant, endInstant, type, chrono);
0481: }
0482:
0483: /**
0484: * Creates a period from the given interval endpoints using the standard
0485: * set of fields.
0486: *
0487: * @param startInstant interval start, null means now
0488: * @param endInstant interval end, null means now
0489: */
0490: public Period(ReadableInstant startInstant,
0491: ReadableInstant endInstant) {
0492: super (startInstant, endInstant, null);
0493: }
0494:
0495: /**
0496: * Creates a period from the given interval endpoints.
0497: *
0498: * @param startInstant interval start, null means now
0499: * @param endInstant interval end, null means now
0500: * @param type which set of fields this period supports, null means standard
0501: */
0502: public Period(ReadableInstant startInstant,
0503: ReadableInstant endInstant, PeriodType type) {
0504: super (startInstant, endInstant, type);
0505: }
0506:
0507: /**
0508: * Creates a period from two partially specified times.
0509: * <p>
0510: * The two partials must contain the same fields, thus you can specify
0511: * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
0512: * but not one of each.
0513: * As these are Partial objects, time zones have no effect on the result.
0514: * <p>
0515: * The two partials must also both be contiguous - see
0516: * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
0517: * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous.
0518: * <p>
0519: * An alternative way of constructing a Period from two Partials
0520: * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}.
0521: * That method handles all kinds of partials.
0522: *
0523: * @param start the start of the period, must not be null
0524: * @param end the end of the period, must not be null
0525: * @throws IllegalArgumentException if the partials are null or invalid
0526: * @since 1.1
0527: */
0528: public Period(ReadablePartial start, ReadablePartial end) {
0529: super (start, end, null);
0530: }
0531:
0532: /**
0533: * Creates a period from two partially specified times.
0534: * <p>
0535: * The two partials must contain the same fields, thus you can specify
0536: * two <code>LocalDate</code> objects, or two <code>LocalTime</code> objects,
0537: * but not one of each.
0538: * As these are Partial objects, time zones have no effect on the result.
0539: * <p>
0540: * The two partials must also both be contiguous - see
0541: * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
0542: * Both <code>LocalDate</code> and <code>LocalTime</code> are contiguous.
0543: * <p>
0544: * An alternative way of constructing a Period from two Partials
0545: * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}.
0546: * That method handles all kinds of partials.
0547: *
0548: * @param start the start of the period, must not be null
0549: * @param end the end of the period, must not be null
0550: * @param type which set of fields this period supports, null means standard
0551: * @throws IllegalArgumentException if the partials are null or invalid
0552: * @since 1.1
0553: */
0554: public Period(ReadablePartial start, ReadablePartial end,
0555: PeriodType type) {
0556: super (start, end, type);
0557: }
0558:
0559: /**
0560: * Creates a period from the given start point and the duration.
0561: *
0562: * @param startInstant the interval start, null means now
0563: * @param duration the duration of the interval, null means zero-length
0564: */
0565: public Period(ReadableInstant startInstant,
0566: ReadableDuration duration) {
0567: super (startInstant, duration, null);
0568: }
0569:
0570: /**
0571: * Creates a period from the given start point and the duration.
0572: *
0573: * @param startInstant the interval start, null means now
0574: * @param duration the duration of the interval, null means zero-length
0575: * @param type which set of fields this period supports, null means standard
0576: */
0577: public Period(ReadableInstant startInstant,
0578: ReadableDuration duration, PeriodType type) {
0579: super (startInstant, duration, type);
0580: }
0581:
0582: /**
0583: * Creates a period from the given duration and end point.
0584: *
0585: * @param duration the duration of the interval, null means zero-length
0586: * @param endInstant the interval end, null means now
0587: */
0588: public Period(ReadableDuration duration, ReadableInstant endInstant) {
0589: super (duration, endInstant, null);
0590: }
0591:
0592: /**
0593: * Creates a period from the given duration and end point.
0594: *
0595: * @param duration the duration of the interval, null means zero-length
0596: * @param endInstant the interval end, null means now
0597: * @param type which set of fields this period supports, null means standard
0598: */
0599: public Period(ReadableDuration duration,
0600: ReadableInstant endInstant, PeriodType type) {
0601: super (duration, endInstant, type);
0602: }
0603:
0604: /**
0605: * Creates a period by converting or copying from another object.
0606: * <p>
0607: * The recognised object types are defined in
0608: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0609: * include ReadablePeriod, ReadableInterval and String.
0610: * The String formats are described by {@link ISOPeriodFormat#standard()}.
0611: *
0612: * @param period period to convert
0613: * @throws IllegalArgumentException if period is invalid
0614: * @throws UnsupportedOperationException if an unsupported field's value is non-zero
0615: */
0616: public Period(Object period) {
0617: super (period, null, null);
0618: }
0619:
0620: /**
0621: * Creates a period by converting or copying from another object.
0622: * <p>
0623: * The recognised object types are defined in
0624: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0625: * include ReadablePeriod, ReadableInterval and String.
0626: * The String formats are described by {@link ISOPeriodFormat#standard()}.
0627: *
0628: * @param period period to convert
0629: * @param type which set of fields this period supports, null means use converter
0630: * @throws IllegalArgumentException if period is invalid
0631: * @throws UnsupportedOperationException if an unsupported field's value is non-zero
0632: */
0633: public Period(Object period, PeriodType type) {
0634: super (period, type, null);
0635: }
0636:
0637: /**
0638: * Creates a period by converting or copying from another object.
0639: * <p>
0640: * The recognised object types are defined in
0641: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0642: * include ReadablePeriod, ReadableInterval and String.
0643: * The String formats are described by {@link ISOPeriodFormat#standard()}.
0644: *
0645: * @param period period to convert
0646: * @param chrono the chronology to use, null means ISO in default zone
0647: * @throws IllegalArgumentException if period is invalid
0648: * @throws UnsupportedOperationException if an unsupported field's value is non-zero
0649: */
0650: public Period(Object period, Chronology chrono) {
0651: super (period, null, chrono);
0652: }
0653:
0654: /**
0655: * Creates a period by converting or copying from another object.
0656: * <p>
0657: * The recognised object types are defined in
0658: * {@link org.joda.time.convert.ConverterManager ConverterManager} and
0659: * include ReadablePeriod, ReadableInterval and String.
0660: * The String formats are described by {@link ISOPeriodFormat#standard()}.
0661: *
0662: * @param period period to convert
0663: * @param type which set of fields this period supports, null means use converter
0664: * @param chrono the chronology to use, null means ISO in default zone
0665: * @throws IllegalArgumentException if period is invalid
0666: * @throws UnsupportedOperationException if an unsupported field's value is non-zero
0667: */
0668: public Period(Object period, PeriodType type, Chronology chrono) {
0669: super (period, type, chrono);
0670: }
0671:
0672: /**
0673: * Constructor used when we trust ourselves.
0674: *
0675: * @param values the values to use, not null, not cloned
0676: * @param type which set of fields this period supports, not null
0677: */
0678: private Period(int[] values, PeriodType type) {
0679: super (values, type);
0680: }
0681:
0682: //-----------------------------------------------------------------------
0683: /**
0684: * Get this period as an immutable <code>Period</code> object
0685: * by returning <code>this</code>.
0686: *
0687: * @return <code>this</code>
0688: */
0689: public Period toPeriod() {
0690: return this ;
0691: }
0692:
0693: //-----------------------------------------------------------------------
0694: /**
0695: * Gets the years field part of the period.
0696: *
0697: * @return the number of years in the period, zero if unsupported
0698: */
0699: public int getYears() {
0700: return getPeriodType().getIndexedField(this ,
0701: PeriodType.YEAR_INDEX);
0702: }
0703:
0704: /**
0705: * Gets the months field part of the period.
0706: *
0707: * @return the number of months in the period, zero if unsupported
0708: */
0709: public int getMonths() {
0710: return getPeriodType().getIndexedField(this ,
0711: PeriodType.MONTH_INDEX);
0712: }
0713:
0714: /**
0715: * Gets the weeks field part of the period.
0716: *
0717: * @return the number of weeks in the period, zero if unsupported
0718: */
0719: public int getWeeks() {
0720: return getPeriodType().getIndexedField(this ,
0721: PeriodType.WEEK_INDEX);
0722: }
0723:
0724: /**
0725: * Gets the days field part of the period.
0726: *
0727: * @return the number of days in the period, zero if unsupported
0728: */
0729: public int getDays() {
0730: return getPeriodType().getIndexedField(this ,
0731: PeriodType.DAY_INDEX);
0732: }
0733:
0734: //-----------------------------------------------------------------------
0735: /**
0736: * Gets the hours field part of the period.
0737: *
0738: * @return the number of hours in the period, zero if unsupported
0739: */
0740: public int getHours() {
0741: return getPeriodType().getIndexedField(this ,
0742: PeriodType.HOUR_INDEX);
0743: }
0744:
0745: /**
0746: * Gets the minutes field part of the period.
0747: *
0748: * @return the number of minutes in the period, zero if unsupported
0749: */
0750: public int getMinutes() {
0751: return getPeriodType().getIndexedField(this ,
0752: PeriodType.MINUTE_INDEX);
0753: }
0754:
0755: /**
0756: * Gets the seconds field part of the period.
0757: *
0758: * @return the number of seconds in the period, zero if unsupported
0759: */
0760: public int getSeconds() {
0761: return getPeriodType().getIndexedField(this ,
0762: PeriodType.SECOND_INDEX);
0763: }
0764:
0765: /**
0766: * Gets the millis field part of the period.
0767: *
0768: * @return the number of millis in the period, zero if unsupported
0769: */
0770: public int getMillis() {
0771: return getPeriodType().getIndexedField(this ,
0772: PeriodType.MILLI_INDEX);
0773: }
0774:
0775: //-----------------------------------------------------------------------
0776: /**
0777: * Creates a new Period instance with the same field values but
0778: * different PeriodType.
0779: * <p>
0780: * This period instance is immutable and unaffected by this method call.
0781: *
0782: * @param type the period type to use, null means standard
0783: * @return the new period instance
0784: * @throws IllegalArgumentException if the new period won't accept all of the current fields
0785: */
0786: public Period withPeriodType(PeriodType type) {
0787: type = DateTimeUtils.getPeriodType(type);
0788: if (type.equals(getPeriodType())) {
0789: return this ;
0790: }
0791: return new Period(this , type);
0792: }
0793:
0794: /**
0795: * Creates a new Period instance with the fields from the specified period
0796: * copied on top of those from this period.
0797: * <p>
0798: * This period instance is immutable and unaffected by this method call.
0799: *
0800: * @param period the period to copy from, null ignored
0801: * @return the new period instance
0802: * @throws IllegalArgumentException if a field type is unsupported
0803: */
0804: public Period withFields(ReadablePeriod period) {
0805: if (period == null) {
0806: return this ;
0807: }
0808: int[] newValues = getValues(); // cloned
0809: newValues = super .mergePeriodInto(newValues, period);
0810: return new Period(newValues, getPeriodType());
0811: }
0812:
0813: //-----------------------------------------------------------------------
0814: /**
0815: * Creates a new Period instance with the specified field set to a new value.
0816: * <p>
0817: * This period instance is immutable and unaffected by this method call.
0818: *
0819: * @param field the field to set, not null
0820: * @param value the value to set to
0821: * @return the new period instance
0822: * @throws IllegalArgumentException if the field type is null or unsupported
0823: */
0824: public Period withField(DurationFieldType field, int value) {
0825: if (field == null) {
0826: throw new IllegalArgumentException("Field must not be null");
0827: }
0828: int[] newValues = getValues(); // cloned
0829: super .setFieldInto(newValues, field, value);
0830: return new Period(newValues, getPeriodType());
0831: }
0832:
0833: /**
0834: * Creates a new Period instance with the valueToAdd added to the specified field.
0835: * <p>
0836: * This period instance is immutable and unaffected by this method call.
0837: *
0838: * @param field the field to set, not null
0839: * @param value the value to add
0840: * @return the new period instance
0841: * @throws IllegalArgumentException if the field type is null or unsupported
0842: */
0843: public Period withFieldAdded(DurationFieldType field, int value) {
0844: if (field == null) {
0845: throw new IllegalArgumentException("Field must not be null");
0846: }
0847: if (value == 0) {
0848: return this ;
0849: }
0850: int[] newValues = getValues(); // cloned
0851: super .addFieldInto(newValues, field, value);
0852: return new Period(newValues, getPeriodType());
0853: }
0854:
0855: //-----------------------------------------------------------------------
0856: /**
0857: * Returns a new period with the specified number of years.
0858: * <p>
0859: * This period instance is immutable and unaffected by this method call.
0860: *
0861: * @param years the amount of years to add, may be negative
0862: * @return the new period with the increased years
0863: * @throws UnsupportedOperationException if the field is not supported
0864: */
0865: public Period withYears(int years) {
0866: int[] values = getValues(); // cloned
0867: getPeriodType().setIndexedField(this , PeriodType.YEAR_INDEX,
0868: values, years);
0869: return new Period(values, getPeriodType());
0870: }
0871:
0872: /**
0873: * Returns a new period with the specified number of months.
0874: * <p>
0875: * This period instance is immutable and unaffected by this method call.
0876: *
0877: * @param months the amount of months to add, may be negative
0878: * @return the new period with the increased months
0879: * @throws UnsupportedOperationException if the field is not supported
0880: */
0881: public Period withMonths(int months) {
0882: int[] values = getValues(); // cloned
0883: getPeriodType().setIndexedField(this , PeriodType.MONTH_INDEX,
0884: values, months);
0885: return new Period(values, getPeriodType());
0886: }
0887:
0888: /**
0889: * Returns a new period with the specified number of weeks.
0890: * <p>
0891: * This period instance is immutable and unaffected by this method call.
0892: *
0893: * @param weeks the amount of weeks to add, may be negative
0894: * @return the new period with the increased weeks
0895: * @throws UnsupportedOperationException if the field is not supported
0896: */
0897: public Period withWeeks(int weeks) {
0898: int[] values = getValues(); // cloned
0899: getPeriodType().setIndexedField(this , PeriodType.WEEK_INDEX,
0900: values, weeks);
0901: return new Period(values, getPeriodType());
0902: }
0903:
0904: /**
0905: * Returns a new period with the specified number of days.
0906: * <p>
0907: * This period instance is immutable and unaffected by this method call.
0908: *
0909: * @param days the amount of days to add, may be negative
0910: * @return the new period with the increased days
0911: * @throws UnsupportedOperationException if the field is not supported
0912: */
0913: public Period withDays(int days) {
0914: int[] values = getValues(); // cloned
0915: getPeriodType().setIndexedField(this , PeriodType.DAY_INDEX,
0916: values, days);
0917: return new Period(values, getPeriodType());
0918: }
0919:
0920: /**
0921: * Returns a new period with the specified number of hours.
0922: * <p>
0923: * This period instance is immutable and unaffected by this method call.
0924: *
0925: * @param hours the amount of hours to add, may be negative
0926: * @return the new period with the increased hours
0927: * @throws UnsupportedOperationException if the field is not supported
0928: */
0929: public Period withHours(int hours) {
0930: int[] values = getValues(); // cloned
0931: getPeriodType().setIndexedField(this , PeriodType.HOUR_INDEX,
0932: values, hours);
0933: return new Period(values, getPeriodType());
0934: }
0935:
0936: /**
0937: * Returns a new period with the specified number of minutes.
0938: * <p>
0939: * This period instance is immutable and unaffected by this method call.
0940: *
0941: * @param minutes the amount of minutes to add, may be negative
0942: * @return the new period with the increased minutes
0943: * @throws UnsupportedOperationException if the field is not supported
0944: */
0945: public Period withMinutes(int minutes) {
0946: int[] values = getValues(); // cloned
0947: getPeriodType().setIndexedField(this , PeriodType.MINUTE_INDEX,
0948: values, minutes);
0949: return new Period(values, getPeriodType());
0950: }
0951:
0952: /**
0953: * Returns a new period with the specified number of seconds.
0954: * <p>
0955: * This period instance is immutable and unaffected by this method call.
0956: *
0957: * @param seconds the amount of seconds to add, may be negative
0958: * @return the new period with the increased seconds
0959: * @throws UnsupportedOperationException if the field is not supported
0960: */
0961: public Period withSeconds(int seconds) {
0962: int[] values = getValues(); // cloned
0963: getPeriodType().setIndexedField(this , PeriodType.SECOND_INDEX,
0964: values, seconds);
0965: return new Period(values, getPeriodType());
0966: }
0967:
0968: /**
0969: * Returns a new period with the specified number of millis.
0970: * <p>
0971: * This period instance is immutable and unaffected by this method call.
0972: *
0973: * @param millis the amount of millis to add, may be negative
0974: * @return the new period with the increased millis
0975: * @throws UnsupportedOperationException if the field is not supported
0976: */
0977: public Period withMillis(int millis) {
0978: int[] values = getValues(); // cloned
0979: getPeriodType().setIndexedField(this , PeriodType.MILLI_INDEX,
0980: values, millis);
0981: return new Period(values, getPeriodType());
0982: }
0983:
0984: //-----------------------------------------------------------------------
0985: /**
0986: * Returns a new period with the specified period added.
0987: * <p>
0988: * Each field of the period is added separately. Thus a period of
0989: * 2 hours 30 minutes plus 3 hours 40 minutes will produce a result
0990: * of 5 hours 70 minutes - see {@link #normalizedStandard()}.
0991: * <p>
0992: * If the period being added contains a non-zero amount for a field that
0993: * is not supported in this period then an exception is thrown.
0994: * <p>
0995: * This period instance is immutable and unaffected by this method call.
0996: *
0997: * @param period the period to add, null adds zero and returns this
0998: * @return the new updated period
0999: * @throws UnsupportedOperationException if any field is not supported
1000: * @since 1.5
1001: */
1002: public Period plus(ReadablePeriod period) {
1003: if (period == null) {
1004: return this ;
1005: }
1006: int[] values = getValues(); // cloned
1007: getPeriodType().addIndexedField(this , PeriodType.YEAR_INDEX,
1008: values, period.get(DurationFieldType.YEARS_TYPE));
1009: getPeriodType().addIndexedField(this , PeriodType.MONTH_INDEX,
1010: values, period.get(DurationFieldType.MONTHS_TYPE));
1011: getPeriodType().addIndexedField(this , PeriodType.WEEK_INDEX,
1012: values, period.get(DurationFieldType.WEEKS_TYPE));
1013: getPeriodType().addIndexedField(this , PeriodType.DAY_INDEX,
1014: values, period.get(DurationFieldType.DAYS_TYPE));
1015: getPeriodType().addIndexedField(this , PeriodType.HOUR_INDEX,
1016: values, period.get(DurationFieldType.HOURS_TYPE));
1017: getPeriodType().addIndexedField(this , PeriodType.MINUTE_INDEX,
1018: values, period.get(DurationFieldType.MINUTES_TYPE));
1019: getPeriodType().addIndexedField(this , PeriodType.SECOND_INDEX,
1020: values, period.get(DurationFieldType.SECONDS_TYPE));
1021: getPeriodType().addIndexedField(this , PeriodType.MILLI_INDEX,
1022: values, period.get(DurationFieldType.MILLIS_TYPE));
1023: return new Period(values, getPeriodType());
1024: }
1025:
1026: //-----------------------------------------------------------------------
1027: /**
1028: * Returns a new period with the specified number of years added.
1029: * <p>
1030: * This period instance is immutable and unaffected by this method call.
1031: *
1032: * @param years the amount of years to add, may be negative
1033: * @return the new period with the increased years
1034: * @throws UnsupportedOperationException if the field is not supported
1035: */
1036: public Period plusYears(int years) {
1037: if (years == 0) {
1038: return this ;
1039: }
1040: int[] values = getValues(); // cloned
1041: getPeriodType().addIndexedField(this , PeriodType.YEAR_INDEX,
1042: values, years);
1043: return new Period(values, getPeriodType());
1044: }
1045:
1046: /**
1047: * Returns a new period plus the specified number of months added.
1048: * <p>
1049: * This period instance is immutable and unaffected by this method call.
1050: *
1051: * @param months the amount of months to add, may be negative
1052: * @return the new period plus the increased months
1053: * @throws UnsupportedOperationException if the field is not supported
1054: */
1055: public Period plusMonths(int months) {
1056: if (months == 0) {
1057: return this ;
1058: }
1059: int[] values = getValues(); // cloned
1060: getPeriodType().addIndexedField(this , PeriodType.MONTH_INDEX,
1061: values, months);
1062: return new Period(values, getPeriodType());
1063: }
1064:
1065: /**
1066: * Returns a new period plus the specified number of weeks added.
1067: * <p>
1068: * This period instance is immutable and unaffected by this method call.
1069: *
1070: * @param weeks the amount of weeks to add, may be negative
1071: * @return the new period plus the increased weeks
1072: * @throws UnsupportedOperationException if the field is not supported
1073: */
1074: public Period plusWeeks(int weeks) {
1075: if (weeks == 0) {
1076: return this ;
1077: }
1078: int[] values = getValues(); // cloned
1079: getPeriodType().addIndexedField(this , PeriodType.WEEK_INDEX,
1080: values, weeks);
1081: return new Period(values, getPeriodType());
1082: }
1083:
1084: /**
1085: * Returns a new period plus the specified number of days added.
1086: * <p>
1087: * This period instance is immutable and unaffected by this method call.
1088: *
1089: * @param days the amount of days to add, may be negative
1090: * @return the new period plus the increased days
1091: * @throws UnsupportedOperationException if the field is not supported
1092: */
1093: public Period plusDays(int days) {
1094: if (days == 0) {
1095: return this ;
1096: }
1097: int[] values = getValues(); // cloned
1098: getPeriodType().addIndexedField(this , PeriodType.DAY_INDEX,
1099: values, days);
1100: return new Period(values, getPeriodType());
1101: }
1102:
1103: /**
1104: * Returns a new period plus the specified number of hours added.
1105: * <p>
1106: * This period instance is immutable and unaffected by this method call.
1107: *
1108: * @param hours the amount of hours to add, may be negative
1109: * @return the new period plus the increased hours
1110: * @throws UnsupportedOperationException if the field is not supported
1111: */
1112: public Period plusHours(int hours) {
1113: if (hours == 0) {
1114: return this ;
1115: }
1116: int[] values = getValues(); // cloned
1117: getPeriodType().addIndexedField(this , PeriodType.HOUR_INDEX,
1118: values, hours);
1119: return new Period(values, getPeriodType());
1120: }
1121:
1122: /**
1123: * Returns a new period plus the specified number of minutes added.
1124: * <p>
1125: * This period instance is immutable and unaffected by this method call.
1126: *
1127: * @param minutes the amount of minutes to add, may be negative
1128: * @return the new period plus the increased minutes
1129: * @throws UnsupportedOperationException if the field is not supported
1130: */
1131: public Period plusMinutes(int minutes) {
1132: if (minutes == 0) {
1133: return this ;
1134: }
1135: int[] values = getValues(); // cloned
1136: getPeriodType().addIndexedField(this , PeriodType.MINUTE_INDEX,
1137: values, minutes);
1138: return new Period(values, getPeriodType());
1139: }
1140:
1141: /**
1142: * Returns a new period plus the specified number of seconds added.
1143: * <p>
1144: * This period instance is immutable and unaffected by this method call.
1145: *
1146: * @param seconds the amount of seconds to add, may be negative
1147: * @return the new period plus the increased seconds
1148: * @throws UnsupportedOperationException if the field is not supported
1149: */
1150: public Period plusSeconds(int seconds) {
1151: if (seconds == 0) {
1152: return this ;
1153: }
1154: int[] values = getValues(); // cloned
1155: getPeriodType().addIndexedField(this , PeriodType.SECOND_INDEX,
1156: values, seconds);
1157: return new Period(values, getPeriodType());
1158: }
1159:
1160: /**
1161: * Returns a new period plus the specified number of millis added.
1162: * <p>
1163: * This period instance is immutable and unaffected by this method call.
1164: *
1165: * @param millis the amount of millis to add, may be negative
1166: * @return the new period plus the increased millis
1167: * @throws UnsupportedOperationException if the field is not supported
1168: */
1169: public Period plusMillis(int millis) {
1170: if (millis == 0) {
1171: return this ;
1172: }
1173: int[] values = getValues(); // cloned
1174: getPeriodType().addIndexedField(this , PeriodType.MILLI_INDEX,
1175: values, millis);
1176: return new Period(values, getPeriodType());
1177: }
1178:
1179: //-----------------------------------------------------------------------
1180: /**
1181: * Returns a new period with the specified period subtracted.
1182: * <p>
1183: * Each field of the period is subtracted separately. Thus a period of
1184: * 3 hours 30 minutes minus 2 hours 40 minutes will produce a result
1185: * of 1 hour and -10 minutes - see {@link #normalizedStandard()}.
1186: * <p>
1187: * If the period being added contains a non-zero amount for a field that
1188: * is not supported in this period then an exception is thrown.
1189: * <p>
1190: * This period instance is immutable and unaffected by this method call.
1191: *
1192: * @param period the period to add, null adds zero and returns this
1193: * @return the new updated period
1194: * @throws UnsupportedOperationException if any field is not supported
1195: * @since 1.5
1196: */
1197: public Period minus(ReadablePeriod period) {
1198: if (period == null) {
1199: return this ;
1200: }
1201: int[] values = getValues(); // cloned
1202: getPeriodType().addIndexedField(this , PeriodType.YEAR_INDEX,
1203: values, -period.get(DurationFieldType.YEARS_TYPE));
1204: getPeriodType().addIndexedField(this , PeriodType.MONTH_INDEX,
1205: values, -period.get(DurationFieldType.MONTHS_TYPE));
1206: getPeriodType().addIndexedField(this , PeriodType.WEEK_INDEX,
1207: values, -period.get(DurationFieldType.WEEKS_TYPE));
1208: getPeriodType().addIndexedField(this , PeriodType.DAY_INDEX,
1209: values, -period.get(DurationFieldType.DAYS_TYPE));
1210: getPeriodType().addIndexedField(this , PeriodType.HOUR_INDEX,
1211: values, -period.get(DurationFieldType.HOURS_TYPE));
1212: getPeriodType().addIndexedField(this , PeriodType.MINUTE_INDEX,
1213: values, -period.get(DurationFieldType.MINUTES_TYPE));
1214: getPeriodType().addIndexedField(this , PeriodType.SECOND_INDEX,
1215: values, -period.get(DurationFieldType.SECONDS_TYPE));
1216: getPeriodType().addIndexedField(this , PeriodType.MILLI_INDEX,
1217: values, -period.get(DurationFieldType.MILLIS_TYPE));
1218: return new Period(values, getPeriodType());
1219: }
1220:
1221: //-----------------------------------------------------------------------
1222: /**
1223: * Returns a new period with the specified number of years taken away.
1224: * <p>
1225: * This period instance is immutable and unaffected by this method call.
1226: *
1227: * @param years the amount of years to take away, may be negative
1228: * @return the new period with the increased years
1229: * @throws UnsupportedOperationException if the field is not supported
1230: */
1231: public Period minusYears(int years) {
1232: return plusYears(-years);
1233: }
1234:
1235: /**
1236: * Returns a new period minus the specified number of months taken away.
1237: * <p>
1238: * This period instance is immutable and unaffected by this method call.
1239: *
1240: * @param months the amount of months to take away, may be negative
1241: * @return the new period minus the increased months
1242: * @throws UnsupportedOperationException if the field is not supported
1243: */
1244: public Period minusMonths(int months) {
1245: return plusMonths(-months);
1246: }
1247:
1248: /**
1249: * Returns a new period minus the specified number of weeks taken away.
1250: * <p>
1251: * This period instance is immutable and unaffected by this method call.
1252: *
1253: * @param weeks the amount of weeks to take away, may be negative
1254: * @return the new period minus the increased weeks
1255: * @throws UnsupportedOperationException if the field is not supported
1256: */
1257: public Period minusWeeks(int weeks) {
1258: return plusWeeks(-weeks);
1259: }
1260:
1261: /**
1262: * Returns a new period minus the specified number of days taken away.
1263: * <p>
1264: * This period instance is immutable and unaffected by this method call.
1265: *
1266: * @param days the amount of days to take away, may be negative
1267: * @return the new period minus the increased days
1268: * @throws UnsupportedOperationException if the field is not supported
1269: */
1270: public Period minusDays(int days) {
1271: return plusDays(-days);
1272: }
1273:
1274: /**
1275: * Returns a new period minus the specified number of hours taken away.
1276: * <p>
1277: * This period instance is immutable and unaffected by this method call.
1278: *
1279: * @param hours the amount of hours to take away, may be negative
1280: * @return the new period minus the increased hours
1281: * @throws UnsupportedOperationException if the field is not supported
1282: */
1283: public Period minusHours(int hours) {
1284: return plusHours(-hours);
1285: }
1286:
1287: /**
1288: * Returns a new period minus the specified number of minutes taken away.
1289: * <p>
1290: * This period instance is immutable and unaffected by this method call.
1291: *
1292: * @param minutes the amount of minutes to take away, may be negative
1293: * @return the new period minus the increased minutes
1294: * @throws UnsupportedOperationException if the field is not supported
1295: */
1296: public Period minusMinutes(int minutes) {
1297: return plusMinutes(-minutes);
1298: }
1299:
1300: /**
1301: * Returns a new period minus the specified number of seconds taken away.
1302: * <p>
1303: * This period instance is immutable and unaffected by this method call.
1304: *
1305: * @param seconds the amount of seconds to take away, may be negative
1306: * @return the new period minus the increased seconds
1307: * @throws UnsupportedOperationException if the field is not supported
1308: */
1309: public Period minusSeconds(int seconds) {
1310: return plusSeconds(-seconds);
1311: }
1312:
1313: /**
1314: * Returns a new period minus the specified number of millis taken away.
1315: * <p>
1316: * This period instance is immutable and unaffected by this method call.
1317: *
1318: * @param millis the amount of millis to take away, may be negative
1319: * @return the new period minus the increased millis
1320: * @throws UnsupportedOperationException if the field is not supported
1321: */
1322: public Period minusMillis(int millis) {
1323: return plusMillis(-millis);
1324: }
1325:
1326: //-----------------------------------------------------------------------
1327: /**
1328: * Converts this period to a period in weeks assuming a
1329: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1330: * <p>
1331: * This method allows you to convert between different types of period.
1332: * However to achieve this it makes the assumption that all
1333: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1334: * all minutes are 60 seconds. This is not true when daylight savings time
1335: * is considered, and may also not be true for some unusual chronologies.
1336: * However, it is included as it is a useful operation for many
1337: * applications and business rules.
1338: * <p>
1339: * If the period contains years or months, an exception will be thrown.
1340: *
1341: * @return a period representing the number of standard weeks in this period
1342: * @throws UnsupportedOperationException if the period contains years or months
1343: * @throws ArithmeticException if the number of weeks is too large to be represented
1344: * @since 1.5
1345: */
1346: public Weeks toStandardWeeks() {
1347: checkYearsAndMonths("Weeks");
1348: long millis = getMillis(); // assign to a long
1349: millis += ((long) getSeconds())
1350: * DateTimeConstants.MILLIS_PER_SECOND;
1351: millis += ((long) getMinutes())
1352: * DateTimeConstants.MILLIS_PER_MINUTE;
1353: millis += ((long) getHours())
1354: * DateTimeConstants.MILLIS_PER_HOUR;
1355: millis += ((long) getDays()) * DateTimeConstants.MILLIS_PER_DAY;
1356: long weeks = ((long) getWeeks()) + millis
1357: / DateTimeConstants.MILLIS_PER_WEEK;
1358: return Weeks.weeks(FieldUtils.safeToInt(weeks));
1359: }
1360:
1361: /**
1362: * Converts this period to a period in days assuming a
1363: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1364: * <p>
1365: * This method allows you to convert between different types of period.
1366: * However to achieve this it makes the assumption that all
1367: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1368: * all minutes are 60 seconds. This is not true when daylight savings time
1369: * is considered, and may also not be true for some unusual chronologies.
1370: * However, it is included as it is a useful operation for many
1371: * applications and business rules.
1372: * <p>
1373: * If the period contains years or months, an exception will be thrown.
1374: *
1375: * @return a period representing the number of standard days in this period
1376: * @throws UnsupportedOperationException if the period contains years or months
1377: * @throws ArithmeticException if the number of days is too large to be represented
1378: * @since 1.5
1379: */
1380: public Days toStandardDays() {
1381: checkYearsAndMonths("Days");
1382: long millis = getMillis(); // assign to a long
1383: millis += ((long) getSeconds())
1384: * DateTimeConstants.MILLIS_PER_SECOND;
1385: millis += ((long) getMinutes())
1386: * DateTimeConstants.MILLIS_PER_MINUTE;
1387: millis += ((long) getHours())
1388: * DateTimeConstants.MILLIS_PER_HOUR;
1389: long days = millis / DateTimeConstants.MILLIS_PER_DAY;
1390: days = FieldUtils.safeAdd(days, getDays());
1391: days = FieldUtils.safeAdd(days, ((long) getWeeks())
1392: * ((long) DateTimeConstants.DAYS_PER_WEEK));
1393: return Days.days(FieldUtils.safeToInt(days));
1394: }
1395:
1396: /**
1397: * Converts this period to a period in hours assuming a
1398: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1399: * <p>
1400: * This method allows you to convert between different types of period.
1401: * However to achieve this it makes the assumption that all
1402: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1403: * all minutes are 60 seconds. This is not true when daylight savings time
1404: * is considered, and may also not be true for some unusual chronologies.
1405: * However, it is included as it is a useful operation for many
1406: * applications and business rules.
1407: * <p>
1408: * If the period contains years or months, an exception will be thrown.
1409: *
1410: * @return a period representing the number of standard hours in this period
1411: * @throws UnsupportedOperationException if the period contains years or months
1412: * @throws ArithmeticException if the number of hours is too large to be represented
1413: * @since 1.5
1414: */
1415: public Hours toStandardHours() {
1416: checkYearsAndMonths("Hours");
1417: long millis = getMillis(); // assign to a long
1418: millis += ((long) getSeconds())
1419: * DateTimeConstants.MILLIS_PER_SECOND;
1420: millis += ((long) getMinutes())
1421: * DateTimeConstants.MILLIS_PER_MINUTE;
1422: long hours = millis / DateTimeConstants.MILLIS_PER_HOUR;
1423: hours = FieldUtils.safeAdd(hours, getHours());
1424: hours = FieldUtils.safeAdd(hours, ((long) getDays())
1425: * ((long) DateTimeConstants.HOURS_PER_DAY));
1426: hours = FieldUtils.safeAdd(hours, ((long) getWeeks())
1427: * ((long) DateTimeConstants.HOURS_PER_WEEK));
1428: return Hours.hours(FieldUtils.safeToInt(hours));
1429: }
1430:
1431: /**
1432: * Converts this period to a period in minutes assuming a
1433: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1434: * <p>
1435: * This method allows you to convert between different types of period.
1436: * However to achieve this it makes the assumption that all
1437: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1438: * all minutes are 60 seconds. This is not true when daylight savings time
1439: * is considered, and may also not be true for some unusual chronologies.
1440: * However, it is included as it is a useful operation for many
1441: * applications and business rules.
1442: * <p>
1443: * If the period contains years or months, an exception will be thrown.
1444: *
1445: * @return a period representing the number of standard minutes in this period
1446: * @throws UnsupportedOperationException if the period contains years or months
1447: * @throws ArithmeticException if the number of minutes is too large to be represented
1448: * @since 1.5
1449: */
1450: public Minutes toStandardMinutes() {
1451: checkYearsAndMonths("Minutes");
1452: long millis = getMillis(); // assign to a long
1453: millis += ((long) getSeconds())
1454: * DateTimeConstants.MILLIS_PER_SECOND;
1455: long minutes = millis / DateTimeConstants.MILLIS_PER_MINUTE;
1456: minutes = FieldUtils.safeAdd(minutes, getMinutes());
1457: minutes = FieldUtils.safeAdd(minutes, ((long) getHours())
1458: * ((long) DateTimeConstants.MINUTES_PER_HOUR));
1459: minutes = FieldUtils.safeAdd(minutes, ((long) getDays())
1460: * ((long) DateTimeConstants.MINUTES_PER_DAY));
1461: minutes = FieldUtils.safeAdd(minutes, ((long) getWeeks())
1462: * ((long) DateTimeConstants.MINUTES_PER_WEEK));
1463: return Minutes.minutes(FieldUtils.safeToInt(minutes));
1464: }
1465:
1466: /**
1467: * Converts this period to a period in seconds assuming a
1468: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1469: * <p>
1470: * This method allows you to convert between different types of period.
1471: * However to achieve this it makes the assumption that all
1472: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1473: * all minutes are 60 seconds. This is not true when daylight savings time
1474: * is considered, and may also not be true for some unusual chronologies.
1475: * However, it is included as it is a useful operation for many
1476: * applications and business rules.
1477: * <p>
1478: * If the period contains years or months, an exception will be thrown.
1479: *
1480: * @return a period representing the number of standard seconds in this period
1481: * @throws UnsupportedOperationException if the period contains years or months
1482: * @throws ArithmeticException if the number of seconds is too large to be represented
1483: * @since 1.5
1484: */
1485: public Seconds toStandardSeconds() {
1486: checkYearsAndMonths("Seconds");
1487: long seconds = getMillis()
1488: / DateTimeConstants.MILLIS_PER_SECOND;
1489: seconds = FieldUtils.safeAdd(seconds, getSeconds());
1490: seconds = FieldUtils.safeAdd(seconds, ((long) getMinutes())
1491: * ((long) DateTimeConstants.SECONDS_PER_MINUTE));
1492: seconds = FieldUtils.safeAdd(seconds, ((long) getHours())
1493: * ((long) DateTimeConstants.SECONDS_PER_HOUR));
1494: seconds = FieldUtils.safeAdd(seconds, ((long) getDays())
1495: * ((long) DateTimeConstants.SECONDS_PER_DAY));
1496: seconds = FieldUtils.safeAdd(seconds, ((long) getWeeks())
1497: * ((long) DateTimeConstants.SECONDS_PER_WEEK));
1498: return Seconds.seconds(FieldUtils.safeToInt(seconds));
1499: }
1500:
1501: //-----------------------------------------------------------------------
1502: /**
1503: * Converts this period to a duration assuming a
1504: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1505: * <p>
1506: * This method allows you to convert from a period to a duration.
1507: * However to achieve this it makes the assumption that all
1508: * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and
1509: * all minutes are 60 seconds. This is not true when daylight savings time
1510: * is considered, and may also not be true for some unusual chronologies.
1511: * However, it is included as it is a useful operation for many
1512: * applications and business rules.
1513: * <p>
1514: * If the period contains years or months, an exception will be thrown.
1515: *
1516: * @return a duration equivalent to this period
1517: * @throws UnsupportedOperationException if the period contains years or months
1518: * @since 1.5
1519: */
1520: public Duration toStandardDuration() {
1521: checkYearsAndMonths("Duration");
1522: long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs
1523: millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
1524: millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
1525: millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
1526: millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY));
1527: millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
1528: return new Duration(millis);
1529: }
1530:
1531: /**
1532: * Check that there are no years or months in the period.
1533: *
1534: * @param destintionType the destination type, not null
1535: * @throws UnsupportedOperationException if the period contains years or months
1536: */
1537: private void checkYearsAndMonths(String destintionType) {
1538: if (getMonths() != 0) {
1539: throw new UnsupportedOperationException(
1540: "Cannot convert to "
1541: + destintionType
1542: + " as this period contains months and months vary in length");
1543: }
1544: if (getYears() != 0) {
1545: throw new UnsupportedOperationException(
1546: "Cannot convert to "
1547: + destintionType
1548: + " as this period contains years and years vary in length");
1549: }
1550: }
1551:
1552: //-----------------------------------------------------------------------
1553: /**
1554: * Normalizes this period using standard rules, assuming a 12 month year,
1555: * 7 day week, 24 hour day, 60 minute hour and 60 second minute.
1556: * <p>
1557: * This method allows you to normalize a period.
1558: * However to achieve this it makes the assumption that all years are
1559: * 12 months, all weeks are 7 days, all days are 24 hours,
1560: * all hours are 60 minutes and all minutes are 60 seconds. This is not
1561: * true when daylight savings time is considered, and may also not be true
1562: * for some chronologies. However, it is included as it is a useful operation
1563: * for many applications and business rules.
1564: * <p>
1565: * If the period contains years or months, then the months will be
1566: * normalized to be between 0 and 11. The days field and below will be
1567: * normalized as necessary, however this will not overflow into the months
1568: * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months.
1569: * But a period of 1 month 40 days will remain as 1 month 40 days.
1570: * <p>
1571: * The result will always have a <code>PeriodType</code> of standard, thus
1572: * days will be grouped into weeks.
1573: *
1574: * @return a normalized period equivalent to this period
1575: * @throws ArithmeticException if any field is too large to be represented
1576: * @since 1.5
1577: */
1578: public Period normalizedStandard() {
1579: return normalizedStandard(PeriodType.standard());
1580: }
1581:
1582: //-----------------------------------------------------------------------
1583: /**
1584: * Normalizes this period using standard rules, assuming a 12 month year,
1585: * 7 day week, 24 hour day, 60 minute hour and 60 second minute,
1586: * providing control over how the result is split into fields.
1587: * <p>
1588: * This method allows you to normalize a period.
1589: * However to achieve this it makes the assumption that all years are
1590: * 12 months, all weeks are 7 days, all days are 24 hours,
1591: * all hours are 60 minutes and all minutes are 60 seconds. This is not
1592: * true when daylight savings time is considered, and may also not be true
1593: * for some chronologies. However, it is included as it is a useful operation
1594: * for many applications and business rules.
1595: * <p>
1596: * If the period contains years or months, then the months will be
1597: * normalized to be between 0 and 11. The days field and below will be
1598: * normalized as necessary, however this will not overflow into the months
1599: * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months.
1600: * But a period of 1 month 40 days will remain as 1 month 40 days.
1601: * <p>
1602: * The PeriodType parameter controls how the result is created. It allows
1603: * you to omit certain fields from the result if desired. For example,
1604: * you may not want the result to include weeks, in which case you pass
1605: * in <code>PeriodType.yearMonthDayTime()</code>.
1606: *
1607: * @param type the period type of the new period, null means standard type
1608: * @return a normalized period equivalent to this period
1609: * @throws ArithmeticException if any field is too large to be represented
1610: * @throws UnsupportedOperationException if this period contains non-zero
1611: * years or months but the specified period type does not support them
1612: * @since 1.5
1613: */
1614: public Period normalizedStandard(PeriodType type) {
1615: long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs
1616: millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
1617: millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
1618: millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
1619: millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY));
1620: millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
1621: Period result = new Period(millis, DateTimeUtils
1622: .getPeriodType(type), ISOChronology.getInstanceUTC());
1623: int years = getYears();
1624: int months = getMonths();
1625: if (years != 0 || months != 0) {
1626: years = FieldUtils.safeAdd(years, months / 12);
1627: months = months % 12;
1628: if (years != 0) {
1629: result = result.withYears(years);
1630: }
1631: if (months != 0) {
1632: result = result.withMonths(months);
1633: }
1634: }
1635: return result;
1636: }
1637:
1638: }
|