001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.base;
017:
018: import org.joda.time.DurationFieldType;
019: import org.joda.time.MutablePeriod;
020: import org.joda.time.Period;
021: import org.joda.time.ReadablePeriod;
022: import org.joda.time.format.ISOPeriodFormat;
023: import org.joda.time.format.PeriodFormatter;
024:
025: /**
026: * AbstractPeriod provides the common behaviour for period classes.
027: * <p>
028: * This class should generally not be used directly by API users. The
029: * {@link ReadablePeriod} interface should be used when different
030: * kinds of periods are to be referenced.
031: * <p>
032: * AbstractPeriod subclasses may be mutable and not thread-safe.
033: *
034: * @author Brian S O'Neill
035: * @author Stephen Colebourne
036: * @since 1.0
037: */
038: public abstract class AbstractPeriod implements ReadablePeriod {
039:
040: /**
041: * Constructor.
042: */
043: protected AbstractPeriod() {
044: super ();
045: }
046:
047: //-----------------------------------------------------------------------
048: /**
049: * Gets an array of the field types that this period supports.
050: * <p>
051: * The fields are returned largest to smallest, for example Hours, Minutes, Seconds.
052: *
053: * @return the fields supported in an array that may be altered, largest to smallest
054: */
055: public DurationFieldType[] getFieldTypes() {
056: DurationFieldType[] result = new DurationFieldType[size()];
057: for (int i = 0; i < result.length; i++) {
058: result[i] = getFieldType(i);
059: }
060: return result;
061: }
062:
063: /**
064: * Gets an array of the value of each of the fields that this period supports.
065: * <p>
066: * The fields are returned largest to smallest, for example Hours, Minutes, Seconds.
067: * Each value corresponds to the same array index as <code>getFields()</code>
068: *
069: * @return the current values of each field in an array that may be altered, largest to smallest
070: */
071: public int[] getValues() {
072: int[] result = new int[size()];
073: for (int i = 0; i < result.length; i++) {
074: result[i] = getValue(i);
075: }
076: return result;
077: }
078:
079: //-----------------------------------------------------------------------
080: /**
081: * Gets the value of one of the fields.
082: * <p>
083: * If the field type specified is not supported by the period then zero
084: * is returned.
085: *
086: * @param type the field type to query, null returns zero
087: * @return the value of that field, zero if field not supported
088: */
089: public int get(DurationFieldType type) {
090: int index = indexOf(type);
091: if (index == -1) {
092: return 0;
093: }
094: return getValue(index);
095: }
096:
097: /**
098: * Checks whether the field specified is supported by this period.
099: *
100: * @param type the type to check, may be null which returns false
101: * @return true if the field is supported
102: */
103: public boolean isSupported(DurationFieldType type) {
104: return getPeriodType().isSupported(type);
105: }
106:
107: /**
108: * Gets the index of the field in this period.
109: *
110: * @param type the type to check, may be null which returns -1
111: * @return the index of -1 if not supported
112: */
113: public int indexOf(DurationFieldType type) {
114: return getPeriodType().indexOf(type);
115: }
116:
117: //-----------------------------------------------------------------------
118: /**
119: * Get this period as an immutable <code>Period</code> object.
120: *
121: * @return a Period using the same field set and values
122: */
123: public Period toPeriod() {
124: return new Period(this );
125: }
126:
127: /**
128: * Get this object as a <code>MutablePeriod</code>.
129: * <p>
130: * This will always return a new <code>MutablePeriod</code> with the same fields.
131: *
132: * @return a MutablePeriod using the same field set and values
133: */
134: public MutablePeriod toMutablePeriod() {
135: return new MutablePeriod(this );
136: }
137:
138: //-----------------------------------------------------------------------
139: /**
140: * Compares this object with the specified object for equality based
141: * on the value of each field. All ReadablePeriod instances are accepted.
142: * <p>
143: * Note that a period of 1 day is not equal to a period of 24 hours,
144: * nor is 1 hour equal to 60 minutes. Only periods with the same amount
145: * in each field are equal.
146: * <p>
147: * This is because periods represent an abstracted definition of a time
148: * period (eg. a day may not actually be 24 hours, it might be 23 or 25
149: * at daylight savings boundary).
150: * <p>
151: * To compare the actual duration of two periods, convert both to
152: * {@link org.joda.time.Duration Duration}s, an operation that emphasises
153: * that the result may differ according to the date you choose.
154: *
155: * @param period a readable period to check against
156: * @return true if all the field values are equal, false if
157: * not or the period is null or of an incorrect type
158: */
159: public boolean equals(Object period) {
160: if (this == period) {
161: return true;
162: }
163: if (period instanceof ReadablePeriod == false) {
164: return false;
165: }
166: ReadablePeriod other = (ReadablePeriod) period;
167: if (size() != other.size()) {
168: return false;
169: }
170: for (int i = 0, isize = size(); i < isize; i++) {
171: if (getValue(i) != other.getValue(i)
172: || getFieldType(i) != other.getFieldType(i)) {
173: return false;
174: }
175: }
176: return true;
177: }
178:
179: /**
180: * Gets a hash code for the period as defined by ReadablePeriod.
181: *
182: * @return a hash code
183: */
184: public int hashCode() {
185: int total = 17;
186: for (int i = 0, isize = size(); i < isize; i++) {
187: total = 27 * total + getValue(i);
188: total = 27 * total + getFieldType(i).hashCode();
189: }
190: return total;
191: }
192:
193: //-----------------------------------------------------------------------
194: /**
195: * Gets the value as a String in the ISO8601 duration format.
196: * <p>
197: * For example, "P6H3M7S" represents 6 hours, 3 minutes, 7 seconds.
198: * <p>
199: * For more control over the output, see
200: * {@link org.joda.time.format.PeriodFormatterBuilder PeriodFormatterBuilder}.
201: *
202: * @return the value as an ISO8601 string
203: */
204: public String toString() {
205: return ISOPeriodFormat.standard().print(this );
206: }
207:
208: //-----------------------------------------------------------------------
209: /**
210: * Uses the specified formatter to convert this period to a String.
211: *
212: * @param formatter the formatter to use, null means use <code>toString()</code>.
213: * @return the formatted string
214: * @since 1.5
215: */
216: public String toString(PeriodFormatter formatter) {
217: if (formatter == null) {
218: return toString();
219: }
220: return formatter.print(this);
221: }
222:
223: }
|