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