1 | /* |
2 | * Copyright 2001-2005 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 Chronology iChronology; |
52 | /** The values of each field in this partial */ |
53 | private 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 specifed index. |
255 | * |
256 | * @param index the index |
257 | * @param value the value to set |
258 | * @throws IndexOutOfBoundsException if the index is invalid |
259 | */ |
260 | protected void setValue(int index, int value) { |
261 | DateTimeField field = getField(index); |
262 | iValues = field.set(this, index, iValues, value); |
263 | } |
264 | |
265 | /** |
266 | * Sets the values of all fields. |
267 | * |
268 | * @param values the array of values |
269 | */ |
270 | protected void setValues(int[] values) { |
271 | getChronology().validate(this, values); |
272 | iValues = values; |
273 | } |
274 | |
275 | //----------------------------------------------------------------------- |
276 | /** |
277 | * Output the date using the specified format pattern. |
278 | * |
279 | * @param pattern the pattern specification, null means use <code>toString</code> |
280 | * @see org.joda.time.format.DateTimeFormat |
281 | */ |
282 | public String toString(String pattern) { |
283 | if (pattern == null) { |
284 | return toString(); |
285 | } |
286 | return DateTimeFormat.forPattern(pattern).print(this); |
287 | } |
288 | |
289 | /** |
290 | * Output the date using the specified format pattern. |
291 | * |
292 | * @param pattern the pattern specification, null means use <code>toString</code> |
293 | * @param locale Locale to use, null means default |
294 | * @see org.joda.time.format.DateTimeFormat |
295 | */ |
296 | public String toString(String pattern, Locale locale) throws IllegalArgumentException { |
297 | if (pattern == null) { |
298 | return toString(); |
299 | } |
300 | return DateTimeFormat.forPattern(pattern).withLocale(locale).print(this); |
301 | } |
302 | |
303 | } |