View Javadoc

1   /*
2    *  Copyright 2001-2011 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 java.io.Serializable;
19  import java.util.Locale;
20  
21  import org.joda.time.Chronology;
22  import org.joda.time.DateTimeField;
23  import org.joda.time.DateTimeUtils;
24  import org.joda.time.ReadablePartial;
25  import org.joda.time.convert.ConverterManager;
26  import org.joda.time.convert.PartialConverter;
27  import org.joda.time.format.DateTimeFormat;
28  import org.joda.time.format.DateTimeFormatter;
29  
30  /**
31   * BasePartial is an abstract implementation of ReadablePartial that stores
32   * data in array and <code>Chronology</code> fields.
33   * <p>
34   * This class should generally not be used directly by API users.
35   * The {@link org.joda.time.ReadablePartial} interface should be used when different 
36   * kinds of partial objects are to be referenced.
37   * <p>
38   * BasePartial subclasses may be mutable and not thread-safe.
39   *
40   * @author Stephen Colebourne
41   * @since 1.0
42   */
43  public abstract class BasePartial
44          extends AbstractPartial
45          implements ReadablePartial, Serializable {
46  
47      /** Serialization version */
48      private static final long serialVersionUID = 2353678632973660L;
49  
50      /** The chronology in use */
51      private final Chronology iChronology;
52      /** The values of each field in this partial */
53      private final int[] iValues;
54  
55      //-----------------------------------------------------------------------
56      /**
57       * Constructs a partial with the current time, using ISOChronology in
58       * the default zone to extract the fields.
59       * <p>
60       * The constructor uses the default time zone, resulting in the local time
61       * being initialised. Once the constructor is complete, all further calculations
62       * are performed without reference to a timezone (by switching to UTC).
63       */
64      protected BasePartial() {
65          this(DateTimeUtils.currentTimeMillis(), null);
66      }
67  
68      /**
69       * Constructs a partial with the current time, using the specified chronology
70       * and zone to extract the fields.
71       * <p>
72       * The constructor uses the time zone of the chronology specified.
73       * Once the constructor is complete, all further calculations are performed
74       * without reference to a timezone (by switching to UTC).
75       *
76       * @param chronology  the chronology, null means ISOChronology in the default zone
77       */
78      protected BasePartial(Chronology chronology) {
79          this(DateTimeUtils.currentTimeMillis(), chronology);
80      }
81  
82      /**
83       * Constructs a partial extracting the partial fields from the specified
84       * milliseconds using the ISOChronology in the default zone.
85       * <p>
86       * The constructor uses the default time zone, resulting in the local time
87       * being initialised. Once the constructor is complete, all further calculations
88       * are performed without reference to a timezone (by switching to UTC).
89       *
90       * @param instant  the milliseconds from 1970-01-01T00:00:00Z
91       */
92      protected BasePartial(long instant) {
93          this(instant, null);
94      }
95  
96      /**
97       * Constructs a partial extracting the partial fields from the specified
98       * milliseconds using the chronology provided.
99       * <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 }