001 /* 002 * Copyright 2001-2011 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 java.io.Serializable; 019 import java.util.Locale; 020 021 import org.joda.time.Chronology; 022 import org.joda.time.DateTimeField; 023 import org.joda.time.DateTimeUtils; 024 import org.joda.time.ReadablePartial; 025 import org.joda.time.convert.ConverterManager; 026 import org.joda.time.convert.PartialConverter; 027 import org.joda.time.format.DateTimeFormat; 028 import org.joda.time.format.DateTimeFormatter; 029 030 /** 031 * BasePartial is an abstract implementation of ReadablePartial that stores 032 * data in array and <code>Chronology</code> fields. 033 * <p> 034 * This class should generally not be used directly by API users. 035 * The {@link org.joda.time.ReadablePartial} interface should be used when different 036 * kinds of partial objects are to be referenced. 037 * <p> 038 * BasePartial subclasses may be mutable and not thread-safe. 039 * 040 * @author Stephen Colebourne 041 * @since 1.0 042 */ 043 public abstract class BasePartial 044 extends AbstractPartial 045 implements ReadablePartial, Serializable { 046 047 /** Serialization version */ 048 private static final long serialVersionUID = 2353678632973660L; 049 050 /** The chronology in use */ 051 private final Chronology iChronology; 052 /** The values of each field in this partial */ 053 private final int[] iValues; 054 055 //----------------------------------------------------------------------- 056 /** 057 * Constructs a partial with the current time, using ISOChronology in 058 * the default zone to extract the fields. 059 * <p> 060 * The constructor uses the default time zone, resulting in the local time 061 * being initialised. Once the constructor is complete, all further calculations 062 * are performed without reference to a timezone (by switching to UTC). 063 */ 064 protected BasePartial() { 065 this(DateTimeUtils.currentTimeMillis(), null); 066 } 067 068 /** 069 * Constructs a partial with the current time, using the specified chronology 070 * and zone to extract the fields. 071 * <p> 072 * The constructor uses the time zone of the chronology specified. 073 * Once the constructor is complete, all further calculations are performed 074 * without reference to a timezone (by switching to UTC). 075 * 076 * @param chronology the chronology, null means ISOChronology in the default zone 077 */ 078 protected BasePartial(Chronology chronology) { 079 this(DateTimeUtils.currentTimeMillis(), chronology); 080 } 081 082 /** 083 * Constructs a partial extracting the partial fields from the specified 084 * milliseconds using the ISOChronology in the default zone. 085 * <p> 086 * The constructor uses the default time zone, resulting in the local time 087 * being initialised. Once the constructor is complete, all further calculations 088 * are performed without reference to a timezone (by switching to UTC). 089 * 090 * @param instant the milliseconds from 1970-01-01T00:00:00Z 091 */ 092 protected BasePartial(long instant) { 093 this(instant, null); 094 } 095 096 /** 097 * Constructs a partial extracting the partial fields from the specified 098 * milliseconds using the chronology provided. 099 * <p> 100 * The constructor uses the time zone of the chronology specified. 101 * Once the constructor is complete, all further calculations are performed 102 * without reference to a timezone (by switching to UTC). 103 * 104 * @param instant the milliseconds from 1970-01-01T00:00:00Z 105 * @param chronology the chronology, null means ISOChronology in the default zone 106 */ 107 protected BasePartial(long instant, Chronology chronology) { 108 super(); 109 chronology = DateTimeUtils.getChronology(chronology); 110 iChronology = chronology.withUTC(); 111 iValues = chronology.get(this, instant); 112 } 113 114 /** 115 * Constructs a partial from an Object that represents a time, using the 116 * specified chronology. 117 * <p> 118 * The recognised object types are defined in 119 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 120 * include ReadableInstant, String, Calendar and Date. 121 * <p> 122 * The constructor uses the time zone of the chronology specified. 123 * Once the constructor is complete, all further calculations are performed 124 * without reference to a timezone (by switching to UTC). 125 * 126 * @param instant the datetime object 127 * @param chronology the chronology, null means use converter 128 * @throws IllegalArgumentException if the date is invalid 129 */ 130 protected BasePartial(Object instant, Chronology chronology) { 131 super(); 132 PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); 133 chronology = converter.getChronology(instant, chronology); 134 chronology = DateTimeUtils.getChronology(chronology); 135 iChronology = chronology.withUTC(); 136 iValues = converter.getPartialValues(this, instant, chronology); 137 } 138 139 /** 140 * Constructs a partial from an Object that represents a time, using the 141 * specified chronology. 142 * <p> 143 * The recognised object types are defined in 144 * {@link org.joda.time.convert.ConverterManager ConverterManager} and 145 * include ReadableInstant, String, Calendar and Date. 146 * <p> 147 * The constructor uses the time zone of the chronology specified. 148 * Once the constructor is complete, all further calculations are performed 149 * without reference to a timezone (by switching to UTC). 150 * 151 * @param instant the datetime object 152 * @param chronology the chronology, null means use converter 153 * @param parser if converting from a String, the given parser is preferred 154 * @throws IllegalArgumentException if the date is invalid 155 * @since 1.3 156 */ 157 protected BasePartial(Object instant, Chronology chronology, DateTimeFormatter parser) { 158 super(); 159 PartialConverter converter = ConverterManager.getInstance().getPartialConverter(instant); 160 chronology = converter.getChronology(instant, chronology); 161 chronology = DateTimeUtils.getChronology(chronology); 162 iChronology = chronology.withUTC(); 163 iValues = converter.getPartialValues(this, instant, chronology, parser); 164 } 165 166 /** 167 * Constructs a partial with specified time field values and chronology. 168 * <p> 169 * The constructor uses the time zone of the chronology specified. 170 * Once the constructor is complete, all further calculations are performed 171 * without reference to a timezone (by switching to UTC). 172 * <p> 173 * The array of values is assigned (not cloned) to the new instance. 174 * 175 * @param values the new set of values 176 * @param chronology the chronology, null means ISOChronology in the default zone 177 * @throws IllegalArgumentException if the values are invalid 178 */ 179 protected BasePartial(int[] values, Chronology chronology) { 180 super(); 181 chronology = DateTimeUtils.getChronology(chronology); 182 iChronology = chronology.withUTC(); 183 chronology.validate(this, values); 184 iValues = values; 185 } 186 187 /** 188 * Private constructor to be used by subclasses only which performs no validation. 189 * <p> 190 * Data is assigned (not cloned) to the new instance. 191 * 192 * @param base the base partial 193 * @param values the new set of values, not cloned, null means use base 194 */ 195 protected BasePartial(BasePartial base, int[] values) { 196 super(); 197 iChronology = base.iChronology; 198 iValues = values; 199 } 200 201 /** 202 * Private constructor to be used by subclasses only which performs no validation. 203 * <p> 204 * Data is assigned (not cloned) to the new instance. 205 * This should not be used by mutable subclasses. 206 * 207 * @param base the base partial 208 * @param chrono the chronology to use, null means use base 209 */ 210 protected BasePartial(BasePartial base, Chronology chrono) { 211 super(); 212 iChronology = chrono.withUTC(); 213 iValues = base.iValues; 214 } 215 216 //----------------------------------------------------------------------- 217 /** 218 * Gets the value of the field at the specifed index. 219 * 220 * @param index the index 221 * @return the value 222 * @throws IndexOutOfBoundsException if the index is invalid 223 */ 224 public int getValue(int index) { 225 return iValues[index]; 226 } 227 228 /** 229 * Gets an array of the value of each of the fields that this partial supports. 230 * <p> 231 * The fields are returned largest to smallest, for example Hour, Minute, Second. 232 * Each value corresponds to the same array index as <code>getFields()</code> 233 * 234 * @return the current values of each field (cloned), largest to smallest 235 */ 236 public int[] getValues() { 237 return (int[]) iValues.clone(); 238 } 239 240 /** 241 * Gets the chronology of the partial which is never null. 242 * <p> 243 * The {@link Chronology} is the calculation engine behind the partial and 244 * provides conversion and validation of the fields in a particular calendar system. 245 * 246 * @return the chronology, never null 247 */ 248 public Chronology getChronology() { 249 return iChronology; 250 } 251 252 //----------------------------------------------------------------------- 253 /** 254 * Sets the value of the field at the specified index. 255 * <p> 256 * In version 2.0 and later, this method copies the array into the original. 257 * This is because the instance variable has been changed to be final to satisfy the Java Memory Model. 258 * This only impacts subclasses that are mutable. 259 * 260 * @param index the index 261 * @param value the value to set 262 * @throws IndexOutOfBoundsException if the index is invalid 263 */ 264 protected void setValue(int index, int value) { 265 DateTimeField field = getField(index); 266 int[] values = field.set(this, index, iValues, value); 267 System.arraycopy(values, 0, iValues, 0, iValues.length); 268 } 269 270 /** 271 * Sets the values of all fields. 272 * <p> 273 * In version 2.0 and later, this method copies the array into the original. 274 * This is because the instance variable has been changed to be final to satisfy the Java Memory Model. 275 * This only impacts subclasses that are mutable. 276 * 277 * @param values the array of values 278 */ 279 protected void setValues(int[] values) { 280 getChronology().validate(this, values); 281 System.arraycopy(values, 0, iValues, 0, iValues.length); 282 } 283 284 //----------------------------------------------------------------------- 285 /** 286 * Output the date using the specified format pattern. 287 * 288 * @param pattern the pattern specification, null means use <code>toString</code> 289 * @see org.joda.time.format.DateTimeFormat 290 */ 291 public String toString(String pattern) { 292 if (pattern == null) { 293 return toString(); 294 } 295 return DateTimeFormat.forPattern(pattern).print(this); 296 } 297 298 /** 299 * Output the date using the specified format pattern. 300 * 301 * @param pattern the pattern specification, null means use <code>toString</code> 302 * @param locale Locale to use, null means default 303 * @see org.joda.time.format.DateTimeFormat 304 */ 305 public String toString(String pattern, Locale locale) throws IllegalArgumentException { 306 if (pattern == null) { 307 return toString(); 308 } 309 return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); 310 } 311 312 }