diff --git a/projects/Time/5/org/joda/time/Period.java b/projects/Time/5/org/joda/time/Period.java new file mode 100644 index 0000000..f404793 --- /dev/null +++ b/projects/Time/5/org/joda/time/Period.java @@ -0,0 +1,1640 @@ +/* + * Copyright 2001-2010 Stephen Colebourne + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.joda.time; + +import java.io.Serializable; + +import org.joda.convert.FromString; +import org.joda.time.base.BasePeriod; +import org.joda.time.chrono.ISOChronology; +import org.joda.time.field.FieldUtils; +import org.joda.time.format.ISOPeriodFormat; +import org.joda.time.format.PeriodFormatter; + +/** + * An immutable time period specifying a set of duration field values. + *
+ * A time period is divided into a number of fields, such as hours and seconds. + * Which fields are supported is defined by the PeriodType class. + * The default is the standard period type, which supports years, months, weeks, days, + * hours, minutes, seconds and millis. + *
+ * When this time period is added to an instant, the effect is of adding each field in turn. + * As a result, this takes into account daylight savings time. + * Adding a time period of 1 day to the day before daylight savings starts will only add + * 23 hours rather than 24 to ensure that the time remains the same. + * If this is not the behaviour you want, then see {@link Duration}. + *
+ * The definition of a period also affects the equals method. A period of 1 + * day is not equal to a period of 24 hours, nor 1 hour equal to 60 minutes. + * This is because periods represent an abstracted definition of a time period + * (eg. a day may not actually be 24 hours, it might be 23 or 25 at daylight + * savings boundary). To compare the actual duration of two periods, convert + * both to durations using toDuration, an operation that emphasises that the + * result may differ according to the date you choose. + *
+ * Period is thread-safe and immutable, provided that the PeriodType is as well. + * All standard PeriodType classes supplied are thread-safe and immutable. + * + * @author Brian S O'Neill + * @author Stephen Colebourne + * @since 1.0 + * @see MutablePeriod + */ +public final class Period + extends BasePeriod + implements ReadablePeriod, Serializable { + + /** + * A period of zero length and standard period type. + * @since 1.4 + */ + public static final Period ZERO = new Period(); + + /** Serialization version */ + private static final long serialVersionUID = 741052353876488155L; + + //----------------------------------------------------------------------- + /** + * Parses a {@code Period} from the specified string. + *
+ * This uses {@link ISOPeriodFormat#standard()}. + * + * @param str the string to parse, not null + * @since 2.0 + */ + @FromString + public static Period parse(String str) { + return parse(str, ISOPeriodFormat.standard()); + } + + /** + * Parses a {@code Period} from the specified string using a formatter. + * + * @param str the string to parse, not null + * @param formatter the formatter to use, not null + * @since 2.0 + */ + public static Period parse(String str, PeriodFormatter formatter) { + return formatter.parsePeriod(str); + } + + //----------------------------------------------------------------------- + /** + * Create a period with a specified number of years. + *
+ * The standard period type is used, thus you can add other fields such
+ * as months or days using the withXxx()
methods.
+ * For example, Period.years(2).withMonths(6);
+ *
+ * If you want a year-based period that cannot have other fields added, + * then you should consider using {@link Years}. + * + * @param years the amount of years in this period + * @return the period + */ + public static Period years(int years) { + return new Period(new int[] {years, 0, 0, 0, 0, 0, 0, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of months. + *
+ * The standard period type is used, thus you can add other fields such
+ * as years or days using the withXxx()
methods.
+ * For example, Period.months(2).withDays(6);
+ *
+ * If you want a month-based period that cannot have other fields added, + * then you should consider using {@link Months}. + * + * @param months the amount of months in this period + * @return the period + */ + public static Period months(int months) { + return new Period(new int[] {0, months, 0, 0, 0, 0, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of weeks. + *
+ * The standard period type is used, thus you can add other fields such
+ * as months or days using the withXxx()
methods.
+ * For example, Period.weeks(2).withDays(6);
+ *
+ * If you want a week-based period that cannot have other fields added, + * then you should consider using {@link Weeks}. + * + * @param weeks the amount of weeks in this period + * @return the period + */ + public static Period weeks(int weeks) { + return new Period(new int[] {0, 0, weeks, 0, 0, 0, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of days. + *
+ * The standard period type is used, thus you can add other fields such
+ * as months or weeks using the withXxx()
methods.
+ * For example, Period.days(2).withHours(6);
+ *
+ * If you want a day-based period that cannot have other fields added, + * then you should consider using {@link Days}. + * + * @param days the amount of days in this period + * @return the period + */ + public static Period days(int days) { + return new Period(new int[] {0, 0, 0, days, 0, 0, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of hours. + *
+ * The standard period type is used, thus you can add other fields such
+ * as months or days using the withXxx()
methods.
+ * For example, Period.hours(2).withMinutes(30);
+ *
+ * If you want a hour-based period that cannot have other fields added, + * then you should consider using {@link Hours}. + * + * @param hours the amount of hours in this period + * @return the period + */ + public static Period hours(int hours) { + return new Period(new int[] {0, 0, 0, 0, hours, 0, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of minutes. + *
+ * The standard period type is used, thus you can add other fields such
+ * as days or hours using the withXxx()
methods.
+ * For example, Period.minutes(2).withSeconds(30);
+ *
+ * If you want a minute-based period that cannot have other fields added, + * then you should consider using {@link Minutes}. + * + * @param minutes the amount of minutes in this period + * @return the period + */ + public static Period minutes(int minutes) { + return new Period(new int[] {0, 0, 0, 0, 0, minutes, 0, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of seconds. + *
+ * The standard period type is used, thus you can add other fields such
+ * as days or hours using the withXxx()
methods.
+ * For example, Period.seconds(2).withMillis(30);
+ *
+ * If you want a second-based period that cannot have other fields added, + * then you should consider using {@link Seconds}. + * + * @param seconds the amount of seconds in this period + * @return the period + */ + public static Period seconds(int seconds) { + return new Period(new int[] {0, 0, 0, 0, 0, 0, seconds, 0}, PeriodType.standard()); + } + + /** + * Create a period with a specified number of millis. + *
+ * The standard period type is used, thus you can add other fields such
+ * as days or hours using the withXxx()
methods.
+ * For example, Period.millis(20).withSeconds(30);
+ *
+ * @param millis the amount of millis in this period
+ * @return the period
+ */
+ public static Period millis(int millis) {
+ return new Period(new int[] {0, 0, 0, 0, 0, 0, 0, millis}, PeriodType.standard());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates a period from two partially specified times, calculating
+ * by field difference.
+ *
+ * The two partials must contain the same fields, thus you can specify
+ * two LocalDate
objects, or two LocalTime
objects,
+ * but not one of each. Also, the partial may not contain overlapping
+ * fields, such as dayOfWeek and dayOfMonth.
+ *
+ * Calculation by field difference works by extracting the difference + * one field at a time and not wrapping into other fields. + * Thus 2005-06-09/2007-04-12 will yield P1Y-2M3D. + *
+ * For example, you have an event that always runs from the 27th of + * each month to the 2nd of the next month. If you calculate this + * period using a standard constructor, then you will get between + * P3D and P6D depending on the month. If you use this method, then + * you will get P1M-25D. This field-difference based period can + * be successfully applied to each month of the year to obtain the + * correct end date for a given start date. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public static Period fieldDifference(ReadablePartial start, ReadablePartial end) { + if (start == null || end == null) { + throw new IllegalArgumentException("ReadablePartial objects must not be null"); + } + if (start.size() != end.size()) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + DurationFieldType[] types = new DurationFieldType[start.size()]; + int[] values = new int[start.size()]; + for (int i = 0, isize = start.size(); i < isize; i++) { + if (start.getFieldType(i) != end.getFieldType(i)) { + throw new IllegalArgumentException("ReadablePartial objects must have the same set of fields"); + } + types[i] = start.getFieldType(i).getDurationType(); + if (i > 0 && types[i - 1] == types[i]) { + throw new IllegalArgumentException("ReadablePartial objects must not have overlapping fields"); + } + values[i] = end.getValue(i) - start.getValue(i); + } + return new Period(values, PeriodType.forFields(types)); + } + + //----------------------------------------------------------------------- + /** + * Creates a new empty period with the standard set of fields. + *
+ * One way to initialise a period is as follows: + *
+ * Period = new Period().withYears(6).withMonths(3).withSeconds(23); + *+ * Bear in mind that this creates four period instances in total, three of + * which are immediately discarded. + * The alterative is more efficient, but less readable: + *
+ * Period = new Period(6, 3, 0, 0, 0, 0, 23, 0); + *+ * The following is also slightly less wasteful: + *
+ * Period = Period.years(6).withMonths(3).withSeconds(23); + *+ */ + public Period() { + super(0L, null, null); + } + + /** + * Create a period from a set of field values using the standard set of fields. + * Note that the parameters specify the time fields hours, minutes, + * seconds and millis, not the date fields. + * + * @param hours amount of hours in this period + * @param minutes amount of minutes in this period + * @param seconds amount of seconds in this period + * @param millis amount of milliseconds in this period + */ + public Period(int hours, int minutes, int seconds, int millis) { + super(0, 0, 0, 0, hours, minutes, seconds, millis, PeriodType.standard()); + } + + /** + * Create a period from a set of field values using the standard set of fields. + * + * @param years amount of years in this period + * @param months amount of months in this period + * @param weeks amount of weeks in this period + * @param days amount of days in this period + * @param hours amount of hours in this period + * @param minutes amount of minutes in this period + * @param seconds amount of seconds in this period + * @param millis amount of milliseconds in this period + */ + public Period(int years, int months, int weeks, int days, + int hours, int minutes, int seconds, int millis) { + super(years, months, weeks, days, hours, minutes, seconds, millis, PeriodType.standard()); + } + + /** + * Create a period from a set of field values. + *
+ * There is usually little need to use this constructor. + * The period type is used primarily to define how to split an interval into a period. + * As this constructor already is split, the period type does no real work. + * + * @param years amount of years in this period, which must be zero if unsupported + * @param months amount of months in this period, which must be zero if unsupported + * @param weeks amount of weeks in this period, which must be zero if unsupported + * @param days amount of days in this period, which must be zero if unsupported + * @param hours amount of hours in this period, which must be zero if unsupported + * @param minutes amount of minutes in this period, which must be zero if unsupported + * @param seconds amount of seconds in this period, which must be zero if unsupported + * @param millis amount of milliseconds in this period, which must be zero if unsupported + * @param type which set of fields this period supports, null means AllType + * @throws IllegalArgumentException if an unsupported field's value is non-zero + */ + public Period(int years, int months, int weeks, int days, + int hours, int minutes, int seconds, int millis, PeriodType type) { + super(years, months, weeks, days, hours, minutes, seconds, millis, type); + } + + /** + * Creates a period from the given millisecond duration using the standard + * set of fields. + *
+ * Only precise fields in the period type will be used. + * For the standard period type this is the time fields only. + * Thus the year, month, week and day fields will not be populated. + *
+ * If the duration is small, less than one day, then this method will perform + * as you might expect and split the fields evenly. + *
+ * If the duration is larger than one day then all the remaining duration will + * be stored in the largest available precise field, hours in this case. + *
+ * For example, a duration equal to (365 + 60 + 5) days will be converted to + * ((365 + 60 + 5) * 24) hours by this constructor. + *
+ * For more control over the conversion process, you have two options: + *
+ * Only precise fields in the period type will be used. + * Imprecise fields will not be populated. + *
+ * If the duration is small then this method will perform + * as you might expect and split the fields evenly. + *
+ * If the duration is large then all the remaining duration will + * be stored in the largest available precise field. + * For details as to which fields are precise, review the period type javadoc. + * + * @param duration the duration, in milliseconds + * @param type which set of fields this period supports, null means standard + */ + public Period(long duration, PeriodType type) { + super(duration, type, null); + } + + /** + * Creates a period from the given millisecond duration using the standard + * set of fields. + *
+ * Only precise fields in the period type will be used. + * Imprecise fields will not be populated. + *
+ * If the duration is small then this method will perform + * as you might expect and split the fields evenly. + *
+ * If the duration is large then all the remaining duration will + * be stored in the largest available precise field. + * For details as to which fields are precise, review the period type javadoc. + * + * @param duration the duration, in milliseconds + * @param chronology the chronology to use to split the duration, null means ISO default + */ + public Period(long duration, Chronology chronology) { + super(duration, null, chronology); + } + + /** + * Creates a period from the given millisecond duration. + *
+ * Only precise fields in the period type will be used. + * Imprecise fields will not be populated. + *
+ * If the duration is small then this method will perform + * as you might expect and split the fields evenly. + *
+ * If the duration is large then all the remaining duration will + * be stored in the largest available precise field. + * For details as to which fields are precise, review the period type javadoc. + * + * @param duration the duration, in milliseconds + * @param type which set of fields this period supports, null means standard + * @param chronology the chronology to use to split the duration, null means ISO default + */ + public Period(long duration, PeriodType type, Chronology chronology) { + super(duration, type, chronology); + } + + /** + * Creates a period from the given interval endpoints using the standard + * set of fields. + * + * @param startInstant interval start, in milliseconds + * @param endInstant interval end, in milliseconds + */ + public Period(long startInstant, long endInstant) { + super(startInstant, endInstant, null, null); + } + + /** + * Creates a period from the given interval endpoints. + * + * @param startInstant interval start, in milliseconds + * @param endInstant interval end, in milliseconds + * @param type which set of fields this period supports, null means standard + */ + public Period(long startInstant, long endInstant, PeriodType type) { + super(startInstant, endInstant, type, null); + } + + /** + * Creates a period from the given interval endpoints using the standard + * set of fields. + * + * @param startInstant interval start, in milliseconds + * @param endInstant interval end, in milliseconds + * @param chrono the chronology to use, null means ISO in default zone + */ + public Period(long startInstant, long endInstant, Chronology chrono) { + super(startInstant, endInstant, null, chrono); + } + + /** + * Creates a period from the given interval endpoints. + * + * @param startInstant interval start, in milliseconds + * @param endInstant interval end, in milliseconds + * @param type which set of fields this period supports, null means standard + * @param chrono the chronology to use, null means ISO in default zone + */ + public Period(long startInstant, long endInstant, PeriodType type, Chronology chrono) { + super(startInstant, endInstant, type, chrono); + } + + /** + * Creates a period between the given instants using the standard set of fields. + *
+ * Most calculations performed by this method have obvious results. + * The special case is where the calculation is from a "long" month to a "short" month. + * Here, the result favours increasing the months field rather than the days. + * For example, 2013-01-31 to 2013-02-28 is treated as one whole month. + * By contrast, 2013-01-31 to 2013-03-30 is treated as one month and 30 days + * (exposed as 4 weeks and 2 days). + * The results are explained by considering that the start date plus the + * calculated period result in the end date. + * + * @param startInstant interval start, null means now + * @param endInstant interval end, null means now + */ + public Period(ReadableInstant startInstant, ReadableInstant endInstant) { + super(startInstant, endInstant, null); + } + + /** + * Creates a period between the given instants. + *
+ * Most calculations performed by this method have obvious results. + * The special case is where the calculation is from a "long" month to a "short" month. + * Here, the result favours increasing the months field rather than the days. + * For example, 2013-01-31 to 2013-02-28 is treated as one whole month. + * By contrast, 2013-01-31 to 2013-03-30 is treated as one month and 30 days. + * The results are explained by considering that the start date plus the + * calculated period result in the end date. + * + * @param startInstant interval start, null means now + * @param endInstant interval end, null means now + * @param type which set of fields this period supports, null means standard + */ + public Period(ReadableInstant startInstant, ReadableInstant endInstant, PeriodType type) { + super(startInstant, endInstant, type); + } + + /** + * Creates a period from two partially specified times. + *
+ * The two partials must contain the same fields, thus you can specify
+ * two LocalDate
objects, or two LocalTime
objects,
+ * but not one of each.
+ * As these are Partial objects, time zones have no effect on the result.
+ *
+ * The two partials must also both be contiguous - see
+ * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
+ * Both LocalDate
and LocalTime
are contiguous.
+ *
+ * Most calculations performed by this method have obvious results. + * The special case is where the calculation is from a "long" month to a "short" month. + * Here, the result favours increasing the months field rather than the days. + * For example, 2013-01-31 to 2013-02-28 is treated as one whole month. + * By contrast, 2013-01-31 to 2013-03-30 is treated as one month and 30 days + * (exposed as 4 weeks and 2 days). + * The results are explained by considering that the start date plus the + * calculated period result in the end date. + *
+ * An alternative way of constructing a Period from two Partials + * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. + * That method handles all kinds of partials. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public Period(ReadablePartial start, ReadablePartial end) { + super(start, end, null); + } + + /** + * Creates a period from two partially specified times. + *
+ * The two partials must contain the same fields, thus you can specify
+ * two LocalDate
objects, or two LocalTime
objects,
+ * but not one of each.
+ * As these are Partial objects, time zones have no effect on the result.
+ *
+ * The two partials must also both be contiguous - see
+ * {@link DateTimeUtils#isContiguous(ReadablePartial)} for a definition.
+ * Both LocalDate
and LocalTime
are contiguous.
+ *
+ * Most calculations performed by this method have obvious results. + * The special case is where the calculation is from a "long" month to a "short" month. + * Here, the result favours increasing the months field rather than the days. + * For example, 2013-01-31 to 2013-02-28 is treated as one whole month. + * By contrast, 2013-01-31 to 2013-03-30 is treated as one month and 30 days. + * The results are explained by considering that the start date plus the + * calculated period result in the end date. + *
+ * An alternative way of constructing a Period from two Partials + * is {@link #fieldDifference(ReadablePartial, ReadablePartial)}. + * That method handles all kinds of partials. + * + * @param start the start of the period, must not be null + * @param end the end of the period, must not be null + * @param type which set of fields this period supports, null means standard + * @throws IllegalArgumentException if the partials are null or invalid + * @since 1.1 + */ + public Period(ReadablePartial start, ReadablePartial end, PeriodType type) { + super(start, end, type); + } + + /** + * Creates a period from the given start point and the duration. + * + * @param startInstant the interval start, null means now + * @param duration the duration of the interval, null means zero-length + */ + public Period(ReadableInstant startInstant, ReadableDuration duration) { + super(startInstant, duration, null); + } + + /** + * Creates a period from the given start point and the duration. + * + * @param startInstant the interval start, null means now + * @param duration the duration of the interval, null means zero-length + * @param type which set of fields this period supports, null means standard + */ + public Period(ReadableInstant startInstant, ReadableDuration duration, PeriodType type) { + super(startInstant, duration, type); + } + + /** + * Creates a period from the given duration and end point. + * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + */ + public Period(ReadableDuration duration, ReadableInstant endInstant) { + super(duration, endInstant, null); + } + + /** + * Creates a period from the given duration and end point. + * + * @param duration the duration of the interval, null means zero-length + * @param endInstant the interval end, null means now + * @param type which set of fields this period supports, null means standard + */ + public Period(ReadableDuration duration, ReadableInstant endInstant, PeriodType type) { + super(duration, endInstant, type); + } + + /** + * Creates a period by converting or copying from another object. + *
+ * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. + * + * @param period period to convert + * @throws IllegalArgumentException if period is invalid + * @throws UnsupportedOperationException if an unsupported field's value is non-zero + */ + public Period(Object period) { + super(period, null, null); + } + + /** + * Creates a period by converting or copying from another object. + *
+ * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. + * + * @param period period to convert + * @param type which set of fields this period supports, null means use converter + * @throws IllegalArgumentException if period is invalid + * @throws UnsupportedOperationException if an unsupported field's value is non-zero + */ + public Period(Object period, PeriodType type) { + super(period, type, null); + } + + /** + * Creates a period by converting or copying from another object. + *
+ * The recognised object types are defined in + * {@link org.joda.time.convert.ConverterManager ConverterManager} and + * include ReadablePeriod, ReadableInterval and String. + * The String formats are described by {@link ISOPeriodFormat#standard()}. + * + * @param period period to convert + * @param chrono the chronology to use, null means ISO in default zone + * @throws IllegalArgumentException if period is invalid + * @throws UnsupportedOperationException if an unsupported field's value is non-zero + */ + public Period(Object period, Chronology chrono) { + super(period, null, chrono); + } + + /** + * Creates a period by converting or copying from another object. + *
+ * The recognised object types are defined in
+ * {@link org.joda.time.convert.ConverterManager ConverterManager} and
+ * include ReadablePeriod, ReadableInterval and String.
+ * The String formats are described by {@link ISOPeriodFormat#standard()}.
+ *
+ * @param period period to convert
+ * @param type which set of fields this period supports, null means use converter
+ * @param chrono the chronology to use, null means ISO in default zone
+ * @throws IllegalArgumentException if period is invalid
+ * @throws UnsupportedOperationException if an unsupported field's value is non-zero
+ */
+ public Period(Object period, PeriodType type, Chronology chrono) {
+ super(period, type, chrono);
+ }
+
+ /**
+ * Constructor used when we trust ourselves.
+ *
+ * @param values the values to use, not null, not cloned
+ * @param type which set of fields this period supports, not null
+ */
+ private Period(int[] values, PeriodType type) {
+ super(values, type);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Get this period as an immutable Period
object
+ * by returning this
.
+ *
+ * @return this
+ */
+ public Period toPeriod() {
+ return this;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the years field part of the period.
+ *
+ * @return the number of years in the period, zero if unsupported
+ */
+ public int getYears() {
+ return getPeriodType().getIndexedField(this, PeriodType.YEAR_INDEX);
+ }
+
+ /**
+ * Gets the months field part of the period.
+ *
+ * @return the number of months in the period, zero if unsupported
+ */
+ public int getMonths() {
+ return getPeriodType().getIndexedField(this, PeriodType.MONTH_INDEX);
+ }
+
+ /**
+ * Gets the weeks field part of the period.
+ *
+ * @return the number of weeks in the period, zero if unsupported
+ */
+ public int getWeeks() {
+ return getPeriodType().getIndexedField(this, PeriodType.WEEK_INDEX);
+ }
+
+ /**
+ * Gets the days field part of the period.
+ *
+ * @return the number of days in the period, zero if unsupported
+ */
+ public int getDays() {
+ return getPeriodType().getIndexedField(this, PeriodType.DAY_INDEX);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Gets the hours field part of the period.
+ *
+ * @return the number of hours in the period, zero if unsupported
+ */
+ public int getHours() {
+ return getPeriodType().getIndexedField(this, PeriodType.HOUR_INDEX);
+ }
+
+ /**
+ * Gets the minutes field part of the period.
+ *
+ * @return the number of minutes in the period, zero if unsupported
+ */
+ public int getMinutes() {
+ return getPeriodType().getIndexedField(this, PeriodType.MINUTE_INDEX);
+ }
+
+ /**
+ * Gets the seconds field part of the period.
+ *
+ * @return the number of seconds in the period, zero if unsupported
+ */
+ public int getSeconds() {
+ return getPeriodType().getIndexedField(this, PeriodType.SECOND_INDEX);
+ }
+
+ /**
+ * Gets the millis field part of the period.
+ *
+ * @return the number of millis in the period, zero if unsupported
+ */
+ public int getMillis() {
+ return getPeriodType().getIndexedField(this, PeriodType.MILLI_INDEX);
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Creates a new Period instance with the same field values but
+ * different PeriodType.
+ *
+ * This period instance is immutable and unaffected by this method call. + * + * @param type the period type to use, null means standard + * @return the new period instance + * @throws IllegalArgumentException if the new period won't accept all of the current fields + */ + public Period withPeriodType(PeriodType type) { + type = DateTimeUtils.getPeriodType(type); + if (type.equals(getPeriodType())) { + return this; + } + return new Period(this, type); + } + + /** + * Creates a new Period instance with the fields from the specified period + * copied on top of those from this period. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param period the period to copy from, null ignored + * @return the new period instance + * @throws IllegalArgumentException if a field type is unsupported + */ + public Period withFields(ReadablePeriod period) { + if (period == null) { + return this; + } + int[] newValues = getValues(); // cloned + newValues = super.mergePeriodInto(newValues, period); + return new Period(newValues, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Creates a new Period instance with the specified field set to a new value. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param field the field to set, not null + * @param value the value to set to + * @return the new period instance + * @throws IllegalArgumentException if the field type is null or unsupported + */ + public Period withField(DurationFieldType field, int value) { + if (field == null) { + throw new IllegalArgumentException("Field must not be null"); + } + int[] newValues = getValues(); // cloned + super.setFieldInto(newValues, field, value); + return new Period(newValues, getPeriodType()); + } + + /** + * Creates a new Period instance with the valueToAdd added to the specified field. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param field the field to set, not null + * @param value the value to add + * @return the new period instance + * @throws IllegalArgumentException if the field type is null or unsupported + */ + public Period withFieldAdded(DurationFieldType field, int value) { + if (field == null) { + throw new IllegalArgumentException("Field must not be null"); + } + if (value == 0) { + return this; + } + int[] newValues = getValues(); // cloned + super.addFieldInto(newValues, field, value); + return new Period(newValues, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new period with the specified number of years. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param years the amount of years to add, may be negative + * @return the new period with the increased years + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withYears(int years) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.YEAR_INDEX, values, years); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of months. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param months the amount of months to add, may be negative + * @return the new period with the increased months + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withMonths(int months) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.MONTH_INDEX, values, months); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of weeks. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to add, may be negative + * @return the new period with the increased weeks + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withWeeks(int weeks) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.WEEK_INDEX, values, weeks); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of days. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param days the amount of days to add, may be negative + * @return the new period with the increased days + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withDays(int days) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.DAY_INDEX, values, days); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of hours. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to add, may be negative + * @return the new period with the increased hours + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withHours(int hours) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.HOUR_INDEX, values, hours); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of minutes. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to add, may be negative + * @return the new period with the increased minutes + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withMinutes(int minutes) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of seconds. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return the new period with the increased seconds + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withSeconds(int seconds) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.SECOND_INDEX, values, seconds); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period with the specified number of millis. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param millis the amount of millis to add, may be negative + * @return the new period with the increased millis + * @throws UnsupportedOperationException if the field is not supported + */ + public Period withMillis(int millis) { + int[] values = getValues(); // cloned + getPeriodType().setIndexedField(this, PeriodType.MILLI_INDEX, values, millis); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new period with the specified period added. + *
+ * Each field of the period is added separately. Thus a period of + * 2 hours 30 minutes plus 3 hours 40 minutes will produce a result + * of 5 hours 70 minutes - see {@link #normalizedStandard()}. + *
+ * If the period being added contains a non-zero amount for a field that + * is not supported in this period then an exception is thrown. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param period the period to add, null adds zero and returns this + * @return the new updated period + * @throws UnsupportedOperationException if any field is not supported + * @since 1.5 + */ + public Period plus(ReadablePeriod period) { + if (period == null) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, period.get(DurationFieldType.YEARS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, period.get(DurationFieldType.MONTHS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, period.get(DurationFieldType.WEEKS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, period.get(DurationFieldType.DAYS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, period.get(DurationFieldType.HOURS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, period.get(DurationFieldType.MINUTES_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, period.get(DurationFieldType.SECONDS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, period.get(DurationFieldType.MILLIS_TYPE)); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new period with the specified number of years added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param years the amount of years to add, may be negative + * @return the new period with the increased years + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusYears(int years) { + if (years == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, years); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of months added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param months the amount of months to add, may be negative + * @return the new period plus the increased months + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusMonths(int months) { + if (months == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, months); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of weeks added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to add, may be negative + * @return the new period plus the increased weeks + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusWeeks(int weeks) { + if (weeks == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, weeks); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of days added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param days the amount of days to add, may be negative + * @return the new period plus the increased days + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusDays(int days) { + if (days == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, days); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of hours added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to add, may be negative + * @return the new period plus the increased hours + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusHours(int hours) { + if (hours == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, hours); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of minutes added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to add, may be negative + * @return the new period plus the increased minutes + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusMinutes(int minutes) { + if (minutes == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, minutes); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of seconds added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to add, may be negative + * @return the new period plus the increased seconds + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusSeconds(int seconds) { + if (seconds == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, seconds); + return new Period(values, getPeriodType()); + } + + /** + * Returns a new period plus the specified number of millis added. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param millis the amount of millis to add, may be negative + * @return the new period plus the increased millis + * @throws UnsupportedOperationException if the field is not supported + */ + public Period plusMillis(int millis) { + if (millis == 0) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, millis); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new period with the specified period subtracted. + *
+ * Each field of the period is subtracted separately. Thus a period of + * 3 hours 30 minutes minus 2 hours 40 minutes will produce a result + * of 1 hour and -10 minutes - see {@link #normalizedStandard()}. + *
+ * If the period being added contains a non-zero amount for a field that + * is not supported in this period then an exception is thrown. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param period the period to add, null adds zero and returns this + * @return the new updated period + * @throws UnsupportedOperationException if any field is not supported + * @since 1.5 + */ + public Period minus(ReadablePeriod period) { + if (period == null) { + return this; + } + int[] values = getValues(); // cloned + getPeriodType().addIndexedField(this, PeriodType.YEAR_INDEX, values, -period.get(DurationFieldType.YEARS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MONTH_INDEX, values, -period.get(DurationFieldType.MONTHS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.WEEK_INDEX, values, -period.get(DurationFieldType.WEEKS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.DAY_INDEX, values, -period.get(DurationFieldType.DAYS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.HOUR_INDEX, values, -period.get(DurationFieldType.HOURS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MINUTE_INDEX, values, -period.get(DurationFieldType.MINUTES_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.SECOND_INDEX, values, -period.get(DurationFieldType.SECONDS_TYPE)); + getPeriodType().addIndexedField(this, PeriodType.MILLI_INDEX, values, -period.get(DurationFieldType.MILLIS_TYPE)); + return new Period(values, getPeriodType()); + } + + //----------------------------------------------------------------------- + /** + * Returns a new period with the specified number of years taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param years the amount of years to take away, may be negative + * @return the new period with the increased years + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusYears(int years) { + return plusYears(-years); + } + + /** + * Returns a new period minus the specified number of months taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param months the amount of months to take away, may be negative + * @return the new period minus the increased months + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusMonths(int months) { + return plusMonths(-months); + } + + /** + * Returns a new period minus the specified number of weeks taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param weeks the amount of weeks to take away, may be negative + * @return the new period minus the increased weeks + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusWeeks(int weeks) { + return plusWeeks(-weeks); + } + + /** + * Returns a new period minus the specified number of days taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param days the amount of days to take away, may be negative + * @return the new period minus the increased days + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusDays(int days) { + return plusDays(-days); + } + + /** + * Returns a new period minus the specified number of hours taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param hours the amount of hours to take away, may be negative + * @return the new period minus the increased hours + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusHours(int hours) { + return plusHours(-hours); + } + + /** + * Returns a new period minus the specified number of minutes taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param minutes the amount of minutes to take away, may be negative + * @return the new period minus the increased minutes + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusMinutes(int minutes) { + return plusMinutes(-minutes); + } + + /** + * Returns a new period minus the specified number of seconds taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param seconds the amount of seconds to take away, may be negative + * @return the new period minus the increased seconds + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusSeconds(int seconds) { + return plusSeconds(-seconds); + } + + /** + * Returns a new period minus the specified number of millis taken away. + *
+ * This period instance is immutable and unaffected by this method call. + * + * @param millis the amount of millis to take away, may be negative + * @return the new period minus the increased millis + * @throws UnsupportedOperationException if the field is not supported + */ + public Period minusMillis(int millis) { + return plusMillis(-millis); + } + + //----------------------------------------------------------------------- + /** + * Returns a new instance with each element in this period multiplied + * by the specified scalar. + * + * @param scalar the scalar to multiply by, not null + * @return a {@code Period} based on this period with the amounts multiplied by the scalar, never null + * @throws ArithmeticException if the capacity of any field is exceeded + * @since 2.1 + */ + public Period multipliedBy(int scalar) { + if (this == ZERO || scalar == 1) { + return this; + } + int[] values = getValues(); // cloned + for (int i = 0; i < values.length; i++) { + values[i] = FieldUtils.safeMultiply(values[i], scalar); + } + return new Period(values, getPeriodType()); + } + + /** + * Returns a new instance with each amount in this period negated. + * + * @return a {@code Period} based on this period with the amounts negated, never null + * @throws ArithmeticException if any field has the minimum value + * @since 2.1 + */ + public Period negated() { + return multipliedBy(-1); + } + + //----------------------------------------------------------------------- + /** + * Converts this period to a period in weeks assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard weeks in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of weeks is too large to be represented + * @since 1.5 + */ + public Weeks toStandardWeeks() { + checkYearsAndMonths("Weeks"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; + millis += ((long) getDays()) * DateTimeConstants.MILLIS_PER_DAY; + long weeks = ((long) getWeeks()) + millis / DateTimeConstants.MILLIS_PER_WEEK; + return Weeks.weeks(FieldUtils.safeToInt(weeks)); + } + + /** + * Converts this period to a period in days assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard days in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of days is too large to be represented + * @since 1.5 + */ + public Days toStandardDays() { + checkYearsAndMonths("Days"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + millis += ((long) getHours()) * DateTimeConstants.MILLIS_PER_HOUR; + long days = millis / DateTimeConstants.MILLIS_PER_DAY; + days = FieldUtils.safeAdd(days, getDays()); + days = FieldUtils.safeAdd(days, ((long) getWeeks()) * ((long) DateTimeConstants.DAYS_PER_WEEK)); + return Days.days(FieldUtils.safeToInt(days)); + } + + /** + * Converts this period to a period in hours assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard hours in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of hours is too large to be represented + * @since 1.5 + */ + public Hours toStandardHours() { + checkYearsAndMonths("Hours"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + millis += ((long) getMinutes()) * DateTimeConstants.MILLIS_PER_MINUTE; + long hours = millis / DateTimeConstants.MILLIS_PER_HOUR; + hours = FieldUtils.safeAdd(hours, getHours()); + hours = FieldUtils.safeAdd(hours, ((long) getDays()) * ((long) DateTimeConstants.HOURS_PER_DAY)); + hours = FieldUtils.safeAdd(hours, ((long) getWeeks()) * ((long) DateTimeConstants.HOURS_PER_WEEK)); + return Hours.hours(FieldUtils.safeToInt(hours)); + } + + /** + * Converts this period to a period in minutes assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard minutes in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of minutes is too large to be represented + * @since 1.5 + */ + public Minutes toStandardMinutes() { + checkYearsAndMonths("Minutes"); + long millis = getMillis(); // assign to a long + millis += ((long) getSeconds()) * DateTimeConstants.MILLIS_PER_SECOND; + long minutes = millis / DateTimeConstants.MILLIS_PER_MINUTE; + minutes = FieldUtils.safeAdd(minutes, getMinutes()); + minutes = FieldUtils.safeAdd(minutes, ((long) getHours()) * ((long) DateTimeConstants.MINUTES_PER_HOUR)); + minutes = FieldUtils.safeAdd(minutes, ((long) getDays()) * ((long) DateTimeConstants.MINUTES_PER_DAY)); + minutes = FieldUtils.safeAdd(minutes, ((long) getWeeks()) * ((long) DateTimeConstants.MINUTES_PER_WEEK)); + return Minutes.minutes(FieldUtils.safeToInt(minutes)); + } + + /** + * Converts this period to a period in seconds assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert between different types of period. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a period representing the number of standard seconds in this period + * @throws UnsupportedOperationException if the period contains years or months + * @throws ArithmeticException if the number of seconds is too large to be represented + * @since 1.5 + */ + public Seconds toStandardSeconds() { + checkYearsAndMonths("Seconds"); + long seconds = getMillis() / DateTimeConstants.MILLIS_PER_SECOND; + seconds = FieldUtils.safeAdd(seconds, getSeconds()); + seconds = FieldUtils.safeAdd(seconds, ((long) getMinutes()) * ((long) DateTimeConstants.SECONDS_PER_MINUTE)); + seconds = FieldUtils.safeAdd(seconds, ((long) getHours()) * ((long) DateTimeConstants.SECONDS_PER_HOUR)); + seconds = FieldUtils.safeAdd(seconds, ((long) getDays()) * ((long) DateTimeConstants.SECONDS_PER_DAY)); + seconds = FieldUtils.safeAdd(seconds, ((long) getWeeks()) * ((long) DateTimeConstants.SECONDS_PER_WEEK)); + return Seconds.seconds(FieldUtils.safeToInt(seconds)); + } + + //----------------------------------------------------------------------- + /** + * Converts this period to a duration assuming a + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to convert from a period to a duration. + * However to achieve this it makes the assumption that all + * weeks are 7 days, all days are 24 hours, all hours are 60 minutes and + * all minutes are 60 seconds. This is not true when daylight savings time + * is considered, and may also not be true for some unusual chronologies. + * However, it is included as it is a useful operation for many + * applications and business rules. + *
+ * If the period contains years or months, an exception will be thrown. + * + * @return a duration equivalent to this period + * @throws UnsupportedOperationException if the period contains years or months + * @since 1.5 + */ + public Duration toStandardDuration() { + checkYearsAndMonths("Duration"); + long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs + millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND)); + millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE)); + millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR)); + millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY)); + millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK)); + return new Duration(millis); + } + + /** + * Check that there are no years or months in the period. + * + * @param destintionType the destination type, not null + * @throws UnsupportedOperationException if the period contains years or months + */ + private void checkYearsAndMonths(String destintionType) { + if (getMonths() != 0) { + throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains months and months vary in length"); + } + if (getYears() != 0) { + throw new UnsupportedOperationException("Cannot convert to " + destintionType + " as this period contains years and years vary in length"); + } + } + + //----------------------------------------------------------------------- + /** + * Normalizes this period using standard rules, assuming a 12 month year, + * 7 day week, 24 hour day, 60 minute hour and 60 second minute. + *
+ * This method allows you to normalize a period. + * However to achieve this it makes the assumption that all years are + * 12 months, all weeks are 7 days, all days are 24 hours, + * all hours are 60 minutes and all minutes are 60 seconds. This is not + * true when daylight savings time is considered, and may also not be true + * for some chronologies. However, it is included as it is a useful operation + * for many applications and business rules. + *
+ * If the period contains years or months, then the months will be + * normalized to be between 0 and 11. The days field and below will be + * normalized as necessary, however this will not overflow into the months + * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. + * But a period of 1 month 40 days will remain as 1 month 40 days. + *
+ * The result will always have a PeriodType
of standard, thus
+ * days will be grouped into weeks.
+ *
+ * @return a normalized period equivalent to this period
+ * @throws ArithmeticException if any field is too large to be represented
+ * @since 1.5
+ */
+ public Period normalizedStandard() {
+ return normalizedStandard(PeriodType.standard());
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Normalizes this period using standard rules, assuming a 12 month year,
+ * 7 day week, 24 hour day, 60 minute hour and 60 second minute,
+ * providing control over how the result is split into fields.
+ *
+ * This method allows you to normalize a period. + * However to achieve this it makes the assumption that all years are + * 12 months, all weeks are 7 days, all days are 24 hours, + * all hours are 60 minutes and all minutes are 60 seconds. This is not + * true when daylight savings time is considered, and may also not be true + * for some chronologies. However, it is included as it is a useful operation + * for many applications and business rules. + *
+ * If the period contains years or months, then the months will be + * normalized to be between 0 and 11. The days field and below will be + * normalized as necessary, however this will not overflow into the months + * field. Thus a period of 1 year 15 months will normalize to 2 years 3 months. + * But a period of 1 month 40 days will remain as 1 month 40 days. + *
+ * The PeriodType parameter controls how the result is created. It allows
+ * you to omit certain fields from the result if desired. For example,
+ * you may not want the result to include weeks, in which case you pass
+ * in PeriodType.yearMonthDayTime()
.
+ *
+ * @param type the period type of the new period, null means standard type
+ * @return a normalized period equivalent to this period
+ * @throws ArithmeticException if any field is too large to be represented
+ * @throws UnsupportedOperationException if this period contains non-zero
+ * years or months but the specified period type does not support them
+ * @since 1.5
+ */
+ public Period normalizedStandard(PeriodType type) {
+ type = DateTimeUtils.getPeriodType(type);
+ long millis = getMillis(); // no overflow can happen, even with Integer.MAX_VALUEs
+ millis += (((long) getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
+ millis += (((long) getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
+ millis += (((long) getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
+ millis += (((long) getDays()) * ((long) DateTimeConstants.MILLIS_PER_DAY));
+ millis += (((long) getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
+ Period result = new Period(millis, type, ISOChronology.getInstanceUTC());
+ int years = getYears();
+ int months = getMonths();
+ if (years != 0 || months != 0) {
+ years = FieldUtils.safeAdd(years, months / 12);
+ months = months % 12;
+ if (years != 0) {
+ result = result.withYears(years);
+ }
+ if (months != 0) {
+ result = result.withMonths(months);
+ }
+ }
+ return result;
+ }
+
+}