View Javadoc

1   /*
2    *  Copyright 2001-2010 Stephen Colebourne
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.joda.time.base;
17  
18  import org.joda.convert.ToString;
19  import org.joda.time.DurationFieldType;
20  import org.joda.time.MutablePeriod;
21  import org.joda.time.Period;
22  import org.joda.time.ReadablePeriod;
23  import org.joda.time.format.ISOPeriodFormat;
24  import org.joda.time.format.PeriodFormatter;
25  
26  /**
27   * AbstractPeriod provides the common behaviour for period classes.
28   * <p>
29   * This class should generally not be used directly by API users. The 
30   * {@link ReadablePeriod} interface should be used when different 
31   * kinds of periods are to be referenced.
32   * <p>
33   * AbstractPeriod subclasses may be mutable and not thread-safe.
34   *
35   * @author Brian S O'Neill
36   * @author Stephen Colebourne
37   * @since 1.0
38   */
39  public abstract class AbstractPeriod implements ReadablePeriod {
40  
41      /**
42       * Constructor.
43       */
44      protected AbstractPeriod() {
45          super();
46      }
47  
48      //-----------------------------------------------------------------------
49      /**
50       * Gets the number of fields that this period supports.
51       *
52       * @return the number of fields supported
53       * @since 2.0 (previously on BasePeriod)
54       */
55      public int size() {
56          return getPeriodType().size();
57      }
58  
59      /**
60       * Gets the field type at the specified index.
61       *
62       * @param index  the index to retrieve
63       * @return the field at the specified index
64       * @throws IndexOutOfBoundsException if the index is invalid
65       * @since 2.0 (previously on BasePeriod)
66       */
67      public DurationFieldType getFieldType(int index) {
68          return getPeriodType().getFieldType(index);
69      }
70  
71      /**
72       * Gets an array of the field types that this period supports.
73       * <p>
74       * The fields are returned largest to smallest, for example Hours, Minutes, Seconds.
75       *
76       * @return the fields supported in an array that may be altered, largest to smallest
77       */
78      public DurationFieldType[] getFieldTypes() {
79          DurationFieldType[] result = new DurationFieldType[size()];
80          for (int i = 0; i < result.length; i++) {
81              result[i] = getFieldType(i);
82          }
83          return result;
84      }
85  
86      /**
87       * Gets an array of the value of each of the fields that this period supports.
88       * <p>
89       * The fields are returned largest to smallest, for example Hours, Minutes, Seconds.
90       * Each value corresponds to the same array index as <code>getFields()</code>
91       *
92       * @return the current values of each field in an array that may be altered, largest to smallest
93       */
94      public int[] getValues() {
95          int[] result = new int[size()];
96          for (int i = 0; i < result.length; i++) {
97              result[i] = getValue(i);
98          }
99          return result;
100     }
101 
102     //-----------------------------------------------------------------------
103     /**
104      * Gets the value of one of the fields.
105      * <p>
106      * If the field type specified is not supported by the period then zero
107      * is returned.
108      *
109      * @param type  the field type to query, null returns zero
110      * @return the value of that field, zero if field not supported
111      */
112     public int get(DurationFieldType type) {
113         int index = indexOf(type);
114         if (index == -1) {
115             return 0;
116         }
117         return getValue(index);
118     }
119 
120     /**
121      * Checks whether the field specified is supported by this period.
122      *
123      * @param type  the type to check, may be null which returns false
124      * @return true if the field is supported
125      */
126     public boolean isSupported(DurationFieldType type) {
127         return getPeriodType().isSupported(type);
128     }
129 
130     /**
131      * Gets the index of the field in this period.
132      *
133      * @param type  the type to check, may be null which returns -1
134      * @return the index of -1 if not supported
135      */
136     public int indexOf(DurationFieldType type) {
137         return getPeriodType().indexOf(type);
138     }
139 
140     //-----------------------------------------------------------------------
141     /**
142      * Get this period as an immutable <code>Period</code> object.
143      * 
144      * @return a Period using the same field set and values
145      */
146     public Period toPeriod() {
147         return new Period(this);
148     }
149 
150     /**
151      * Get this object as a <code>MutablePeriod</code>.
152      * <p>
153      * This will always return a new <code>MutablePeriod</code> with the same fields.
154      * 
155      * @return a MutablePeriod using the same field set and values
156      */
157     public MutablePeriod toMutablePeriod() {
158         return new MutablePeriod(this);
159     }
160 
161     //-----------------------------------------------------------------------
162     /**
163      * Compares this object with the specified object for equality based
164      * on the value of each field. All ReadablePeriod instances are accepted.
165      * <p>
166      * Note that a period of 1 day is not equal to a period of 24 hours,
167      * nor is 1 hour equal to 60 minutes. Only periods with the same amount
168      * in each field are equal.
169      * <p>
170      * This is because periods represent an abstracted definition of a time
171      * period (eg. a day may not actually be 24 hours, it might be 23 or 25
172      * at daylight savings boundary).
173      * <p>
174      * To compare the actual duration of two periods, convert both to
175      * {@link org.joda.time.Duration Duration}s, an operation that emphasises
176      * that the result may differ according to the date you choose.
177      *
178      * @param period  a readable period to check against
179      * @return true if all the field values are equal, false if
180      *  not or the period is null or of an incorrect type
181      */
182     public boolean equals(Object period) {
183         if (this == period) {
184             return true;
185         }
186         if (period instanceof ReadablePeriod == false) {
187             return false;
188         }
189         ReadablePeriod other = (ReadablePeriod) period;
190         if (size() != other.size()) {
191             return false;
192         }
193         for (int i = 0, isize = size(); i < isize; i++) {
194             if (getValue(i) != other.getValue(i) || getFieldType(i) != other.getFieldType(i)) {
195                 return false;
196             }
197         }
198         return true;
199     }
200 
201     /**
202      * Gets a hash code for the period as defined by ReadablePeriod.
203      *
204      * @return a hash code
205      */
206     public int hashCode() {
207         int total = 17;
208         for (int i = 0, isize = size(); i < isize; i++) {
209             total = 27 * total + getValue(i);
210             total = 27 * total + getFieldType(i).hashCode();
211         }
212         return total;
213     }
214 
215     //-----------------------------------------------------------------------
216     /**
217      * Gets the value as a String in the ISO8601 duration format.
218      * <p>
219      * For example, "P6H3M7S" represents 6 hours, 3 minutes, 7 seconds.
220      * <p>
221      * For more control over the output, see
222      * {@link org.joda.time.format.PeriodFormatterBuilder PeriodFormatterBuilder}.
223      *
224      * @return the value as an ISO8601 string
225      */
226     @ToString
227     public String toString() {
228         return ISOPeriodFormat.standard().print(this);
229     }
230 
231     //-----------------------------------------------------------------------
232     /**
233      * Uses the specified formatter to convert this period to a String.
234      *
235      * @param formatter  the formatter to use, null means use <code>toString()</code>.
236      * @return the formatted string
237      * @since 1.5
238      */
239     public String toString(PeriodFormatter formatter) {
240         if (formatter == null) {
241             return toString();
242         }
243         return formatter.print(this);
244     }
245 
246 }