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) || getFieldType(i) != other.getFieldType(i)) { 172 return false; 173 } 174 } 175 return true; 176 } 177 178 /** 179 * Gets a hash code for the period as defined by ReadablePeriod. 180 * 181 * @return a hash code 182 */ 183 public int hashCode() { 184 int total = 17; 185 for (int i = 0, isize = size(); i < isize; i++) { 186 total = 27 * total + getValue(i); 187 total = 27 * total + getFieldType(i).hashCode(); 188 } 189 return total; 190 } 191 192 //----------------------------------------------------------------------- 193 /** 194 * Gets the value as a String in the ISO8601 duration format. 195 * <p> 196 * For example, "P6H3M7S" represents 6 hours, 3 minutes, 7 seconds. 197 * <p> 198 * For more control over the output, see 199 * {@link org.joda.time.format.PeriodFormatterBuilder PeriodFormatterBuilder}. 200 * 201 * @return the value as an ISO8601 string 202 */ 203 public String toString() { 204 return ISOPeriodFormat.standard().print(this); 205 } 206 207 //----------------------------------------------------------------------- 208 /** 209 * Uses the specified formatter to convert this period to a String. 210 * 211 * @param formatter the formatter to use, null means use <code>toString()</code>. 212 * @return the formatted string 213 * @since 1.5 214 */ 215 public String toString(PeriodFormatter formatter) { 216 if (formatter == null) { 217 return toString(); 218 } 219 return formatter.print(this); 220 } 221 222 }