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.chrono;
017
018 import java.io.IOException;
019 import java.io.ObjectInputStream;
020
021 import org.joda.time.Chronology;
022 import org.joda.time.DateTimeField;
023 import org.joda.time.DateTimeZone;
024 import org.joda.time.DurationField;
025
026 /**
027 * Abstract Chronology that enables chronologies to be assembled from
028 * a container of fields.
029 * <p>
030 * AssembledChronology is thread-safe and immutable.
031 *
032 * @author Brian S O'Neill
033 * @since 1.0
034 */
035 public abstract class AssembledChronology extends BaseChronology {
036
037 private static final long serialVersionUID = -6728465968995518215L;
038
039 private final Chronology iBase;
040 private final Object iParam;
041
042 private transient DurationField iMillis;
043 private transient DurationField iSeconds;
044 private transient DurationField iMinutes;
045 private transient DurationField iHours;
046 private transient DurationField iHalfdays;
047
048 private transient DurationField iDays;
049 private transient DurationField iWeeks;
050 private transient DurationField iWeekyears;
051 private transient DurationField iMonths;
052 private transient DurationField iYears;
053 private transient DurationField iCenturies;
054 private transient DurationField iEras;
055
056 private transient DateTimeField iMillisOfSecond;
057 private transient DateTimeField iMillisOfDay;
058 private transient DateTimeField iSecondOfMinute;
059 private transient DateTimeField iSecondOfDay;
060 private transient DateTimeField iMinuteOfHour;
061 private transient DateTimeField iMinuteOfDay;
062 private transient DateTimeField iHourOfDay;
063 private transient DateTimeField iClockhourOfDay;
064 private transient DateTimeField iHourOfHalfday;
065 private transient DateTimeField iClockhourOfHalfday;
066 private transient DateTimeField iHalfdayOfDay;
067
068 private transient DateTimeField iDayOfWeek;
069 private transient DateTimeField iDayOfMonth;
070 private transient DateTimeField iDayOfYear;
071 private transient DateTimeField iWeekOfWeekyear;
072 private transient DateTimeField iWeekyear;
073 private transient DateTimeField iWeekyearOfCentury;
074 private transient DateTimeField iMonthOfYear;
075 private transient DateTimeField iYear;
076 private transient DateTimeField iYearOfEra;
077 private transient DateTimeField iYearOfCentury;
078 private transient DateTimeField iCenturyOfEra;
079 private transient DateTimeField iEra;
080
081 // Bit set determines which base fields are used
082 // bit 1 set: hourOfDay, minuteOfHour, secondOfMinute, and millisOfSecond fields
083 // bit 2 set: millisOfDayField
084 // bit 3 set: year, monthOfYear, and dayOfMonth fields
085 private transient int iBaseFlags;
086
087 /**
088 * Constructor calls the assemble method, enabling subclasses to define its
089 * supported fields. If a base chronology is supplied, the field set
090 * initially contains references to each base chronology field.
091 * <p>
092 * Other methods in this class will delegate to the base chronology, if it
093 * can be determined that the base chronology will produce the same results
094 * as AbstractChronology.
095 *
096 * @param base optional base chronology to copy initial fields from
097 * @param param optional param object avalable for assemble method
098 */
099 protected AssembledChronology(Chronology base, Object param) {
100 iBase = base;
101 iParam = param;
102 setFields();
103 }
104
105 public DateTimeZone getZone() {
106 Chronology base;
107 if ((base = iBase) != null) {
108 return base.getZone();
109 }
110 return null;
111 }
112
113 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
114 int millisOfDay)
115 throws IllegalArgumentException
116 {
117 Chronology base;
118 if ((base = iBase) != null && (iBaseFlags & 6) == 6) {
119 // Only call specialized implementation if applicable fields are the same.
120 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
121 }
122 return super.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
123 }
124
125 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
126 int hourOfDay, int minuteOfHour,
127 int secondOfMinute, int millisOfSecond)
128 throws IllegalArgumentException
129 {
130 Chronology base;
131 if ((base = iBase) != null && (iBaseFlags & 5) == 5) {
132 // Only call specialized implementation if applicable fields are the same.
133 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth,
134 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
135 }
136 return super.getDateTimeMillis(year, monthOfYear, dayOfMonth,
137 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
138 }
139
140 public long getDateTimeMillis(long instant,
141 int hourOfDay, int minuteOfHour,
142 int secondOfMinute, int millisOfSecond)
143 throws IllegalArgumentException
144 {
145 Chronology base;
146 if ((base = iBase) != null && (iBaseFlags & 1) == 1) {
147 // Only call specialized implementation if applicable fields are the same.
148 return base.getDateTimeMillis
149 (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
150 }
151 return super.getDateTimeMillis
152 (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
153 }
154
155 public final DurationField millis() {
156 return iMillis;
157 }
158
159 public final DateTimeField millisOfSecond() {
160 return iMillisOfSecond;
161 }
162
163 public final DateTimeField millisOfDay() {
164 return iMillisOfDay;
165 }
166
167 public final DurationField seconds() {
168 return iSeconds;
169 }
170
171 public final DateTimeField secondOfMinute() {
172 return iSecondOfMinute;
173 }
174
175 public final DateTimeField secondOfDay() {
176 return iSecondOfDay;
177 }
178
179 public final DurationField minutes() {
180 return iMinutes;
181 }
182
183 public final DateTimeField minuteOfHour() {
184 return iMinuteOfHour;
185 }
186
187 public final DateTimeField minuteOfDay() {
188 return iMinuteOfDay;
189 }
190
191 public final DurationField hours() {
192 return iHours;
193 }
194
195 public final DateTimeField hourOfDay() {
196 return iHourOfDay;
197 }
198
199 public final DateTimeField clockhourOfDay() {
200 return iClockhourOfDay;
201 }
202
203 public final DurationField halfdays() {
204 return iHalfdays;
205 }
206
207 public final DateTimeField hourOfHalfday() {
208 return iHourOfHalfday;
209 }
210
211 public final DateTimeField clockhourOfHalfday() {
212 return iClockhourOfHalfday;
213 }
214
215 public final DateTimeField halfdayOfDay() {
216 return iHalfdayOfDay;
217 }
218
219 public final DurationField days() {
220 return iDays;
221 }
222
223 public final DateTimeField dayOfWeek() {
224 return iDayOfWeek;
225 }
226
227 public final DateTimeField dayOfMonth() {
228 return iDayOfMonth;
229 }
230
231 public final DateTimeField dayOfYear() {
232 return iDayOfYear;
233 }
234
235 public final DurationField weeks() {
236 return iWeeks;
237 }
238
239 public final DateTimeField weekOfWeekyear() {
240 return iWeekOfWeekyear;
241 }
242
243 public final DurationField weekyears() {
244 return iWeekyears;
245 }
246
247 public final DateTimeField weekyear() {
248 return iWeekyear;
249 }
250
251 public final DateTimeField weekyearOfCentury() {
252 return iWeekyearOfCentury;
253 }
254
255 public final DurationField months() {
256 return iMonths;
257 }
258
259 public final DateTimeField monthOfYear() {
260 return iMonthOfYear;
261 }
262
263 public final DurationField years() {
264 return iYears;
265 }
266
267 public final DateTimeField year() {
268 return iYear;
269 }
270
271 public final DateTimeField yearOfEra() {
272 return iYearOfEra;
273 }
274
275 public final DateTimeField yearOfCentury() {
276 return iYearOfCentury;
277 }
278
279 public final DurationField centuries() {
280 return iCenturies;
281 }
282
283 public final DateTimeField centuryOfEra() {
284 return iCenturyOfEra;
285 }
286
287 public final DurationField eras() {
288 return iEras;
289 }
290
291 public final DateTimeField era() {
292 return iEra;
293 }
294
295 /**
296 * Invoked by the constructor and after deserialization to allow subclasses
297 * to define all of its supported fields. All unset fields default to
298 * unsupported instances.
299 *
300 * @param fields container of fields
301 */
302 protected abstract void assemble(Fields fields);
303
304 /**
305 * Returns the same base chronology as passed into the constructor.
306 */
307 protected final Chronology getBase() {
308 return iBase;
309 }
310
311 /**
312 * Returns the same param object as passed into the constructor.
313 */
314 protected final Object getParam() {
315 return iParam;
316 }
317
318 private void setFields() {
319 Fields fields = new Fields();
320 if (iBase != null) {
321 fields.copyFieldsFrom(iBase);
322 }
323 assemble(fields);
324
325 {
326 DurationField f;
327 iMillis = (f = fields.millis) != null ? f : super.millis();
328 iSeconds = (f = fields.seconds) != null ? f : super.seconds();
329 iMinutes = (f = fields.minutes) != null ? f : super.minutes();
330 iHours = (f = fields.hours) != null ? f : super.hours();
331 iHalfdays = (f = fields.halfdays) != null ? f : super.halfdays();
332 iDays = (f = fields.days) != null ? f : super.days();
333 iWeeks = (f = fields.weeks) != null ? f : super.weeks();
334 iWeekyears = (f = fields.weekyears) != null ? f : super.weekyears();
335 iMonths = (f = fields.months) != null ? f : super.months();
336 iYears = (f = fields.years) != null ? f : super.years();
337 iCenturies = (f = fields.centuries) != null ? f : super.centuries();
338 iEras = (f = fields.eras) != null ? f : super.eras();
339 }
340
341 {
342 DateTimeField f;
343 iMillisOfSecond = (f = fields.millisOfSecond) != null ? f : super.millisOfSecond();
344 iMillisOfDay = (f = fields.millisOfDay) != null ? f : super.millisOfDay();
345 iSecondOfMinute = (f = fields.secondOfMinute) != null ? f : super.secondOfMinute();
346 iSecondOfDay = (f = fields.secondOfDay) != null ? f : super.secondOfDay();
347 iMinuteOfHour = (f = fields.minuteOfHour) != null ? f : super.minuteOfHour();
348 iMinuteOfDay = (f = fields.minuteOfDay) != null ? f : super.minuteOfDay();
349 iHourOfDay = (f = fields.hourOfDay) != null ? f : super.hourOfDay();
350 iClockhourOfDay = (f = fields.clockhourOfDay) != null ? f : super.clockhourOfDay();
351 iHourOfHalfday = (f = fields.hourOfHalfday) != null ? f : super.hourOfHalfday();
352 iClockhourOfHalfday = (f = fields.clockhourOfHalfday) != null ? f : super.clockhourOfHalfday();
353 iHalfdayOfDay = (f = fields.halfdayOfDay) != null ? f : super.halfdayOfDay();
354 iDayOfWeek = (f = fields.dayOfWeek) != null ? f : super.dayOfWeek();
355 iDayOfMonth = (f = fields.dayOfMonth) != null ? f : super.dayOfMonth();
356 iDayOfYear = (f = fields.dayOfYear) != null ? f : super.dayOfYear();
357 iWeekOfWeekyear = (f = fields.weekOfWeekyear) != null ? f : super.weekOfWeekyear();
358 iWeekyear = (f = fields.weekyear) != null ? f : super.weekyear();
359 iWeekyearOfCentury = (f = fields.weekyearOfCentury) != null ? f : super.weekyearOfCentury();
360 iMonthOfYear = (f = fields.monthOfYear) != null ? f : super.monthOfYear();
361 iYear = (f = fields.year) != null ? f : super.year();
362 iYearOfEra = (f = fields.yearOfEra) != null ? f : super.yearOfEra();
363 iYearOfCentury = (f = fields.yearOfCentury) != null ? f : super.yearOfCentury();
364 iCenturyOfEra = (f = fields.centuryOfEra) != null ? f : super.centuryOfEra();
365 iEra = (f = fields.era) != null ? f : super.era();
366 }
367
368 int flags;
369 if (iBase == null) {
370 flags = 0;
371 } else {
372 flags =
373 ((iHourOfDay == iBase.hourOfDay() &&
374 iMinuteOfHour == iBase.minuteOfHour() &&
375 iSecondOfMinute == iBase.secondOfMinute() &&
376 iMillisOfSecond == iBase.millisOfSecond() ) ? 1 : 0) |
377
378 ((iMillisOfDay == iBase.millisOfDay()) ? 2 : 0) |
379
380 ((iYear == iBase.year() &&
381 iMonthOfYear == iBase.monthOfYear() &&
382 iDayOfMonth == iBase.dayOfMonth() ) ? 4 : 0);
383 }
384
385 iBaseFlags = flags;
386 }
387
388 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
389 in.defaultReadObject();
390 setFields();
391 }
392
393 /**
394 * A container of fields used for assembling a chronology.
395 */
396 public static final class Fields {
397 public DurationField millis;
398 public DurationField seconds;
399 public DurationField minutes;
400 public DurationField hours;
401 public DurationField halfdays;
402
403 public DurationField days;
404 public DurationField weeks;
405 public DurationField weekyears;
406 public DurationField months;
407 public DurationField years;
408 public DurationField centuries;
409 public DurationField eras;
410
411 public DateTimeField millisOfSecond;
412 public DateTimeField millisOfDay;
413 public DateTimeField secondOfMinute;
414 public DateTimeField secondOfDay;
415 public DateTimeField minuteOfHour;
416 public DateTimeField minuteOfDay;
417 public DateTimeField hourOfDay;
418 public DateTimeField clockhourOfDay;
419 public DateTimeField hourOfHalfday;
420 public DateTimeField clockhourOfHalfday;
421 public DateTimeField halfdayOfDay;
422
423 public DateTimeField dayOfWeek;
424 public DateTimeField dayOfMonth;
425 public DateTimeField dayOfYear;
426 public DateTimeField weekOfWeekyear;
427 public DateTimeField weekyear;
428 public DateTimeField weekyearOfCentury;
429 public DateTimeField monthOfYear;
430 public DateTimeField year;
431 public DateTimeField yearOfEra;
432 public DateTimeField yearOfCentury;
433 public DateTimeField centuryOfEra;
434 public DateTimeField era;
435
436 Fields() {
437 }
438
439 /**
440 * Copy the supported fields from a chronology into this container.
441 */
442 public void copyFieldsFrom(Chronology chrono) {
443 {
444 DurationField f;
445 if (isSupported(f = chrono.millis())) {
446 millis = f;
447 }
448 if (isSupported(f = chrono.seconds())) {
449 seconds = f;
450 }
451 if (isSupported(f = chrono.minutes())) {
452 minutes = f;
453 }
454 if (isSupported(f = chrono.hours())) {
455 hours = f;
456 }
457 if (isSupported(f = chrono.halfdays())) {
458 halfdays = f;
459 }
460 if (isSupported(f = chrono.days())) {
461 days = f;
462 }
463 if (isSupported(f = chrono.weeks())) {
464 weeks = f;
465 }
466 if (isSupported(f = chrono.weekyears())) {
467 weekyears = f;
468 }
469 if (isSupported(f = chrono.months())) {
470 months = f;
471 }
472 if (isSupported(f = chrono.years())) {
473 years = f;
474 }
475 if (isSupported(f = chrono.centuries())) {
476 centuries = f;
477 }
478 if (isSupported(f = chrono.eras())) {
479 eras = f;
480 }
481 }
482
483 {
484 DateTimeField f;
485 if (isSupported(f = chrono.millisOfSecond())) {
486 millisOfSecond = f;
487 }
488 if (isSupported(f = chrono.millisOfDay())) {
489 millisOfDay = f;
490 }
491 if (isSupported(f = chrono.secondOfMinute())) {
492 secondOfMinute = f;
493 }
494 if (isSupported(f = chrono.secondOfDay())) {
495 secondOfDay = f;
496 }
497 if (isSupported(f = chrono.minuteOfHour())) {
498 minuteOfHour = f;
499 }
500 if (isSupported(f = chrono.minuteOfDay())) {
501 minuteOfDay = f;
502 }
503 if (isSupported(f = chrono.hourOfDay())) {
504 hourOfDay = f;
505 }
506 if (isSupported(f = chrono.clockhourOfDay())) {
507 clockhourOfDay = f;
508 }
509 if (isSupported(f = chrono.hourOfHalfday())) {
510 hourOfHalfday = f;
511 }
512 if (isSupported(f = chrono.clockhourOfHalfday())) {
513 clockhourOfHalfday = f;
514 }
515 if (isSupported(f = chrono.halfdayOfDay())) {
516 halfdayOfDay = f;
517 }
518 if (isSupported(f = chrono.dayOfWeek())) {
519 dayOfWeek = f;
520 }
521 if (isSupported(f = chrono.dayOfMonth())) {
522 dayOfMonth = f;
523 }
524 if (isSupported(f = chrono.dayOfYear())) {
525 dayOfYear = f;
526 }
527 if (isSupported(f = chrono.weekOfWeekyear())) {
528 weekOfWeekyear = f;
529 }
530 if (isSupported(f = chrono.weekyear())) {
531 weekyear = f;
532 }
533 if (isSupported(f = chrono.weekyearOfCentury())) {
534 weekyearOfCentury = f;
535 }
536 if (isSupported(f = chrono.monthOfYear())) {
537 monthOfYear = f;
538 }
539 if (isSupported(f = chrono.year())) {
540 year = f;
541 }
542 if (isSupported(f = chrono.yearOfEra())) {
543 yearOfEra = f;
544 }
545 if (isSupported(f = chrono.yearOfCentury())) {
546 yearOfCentury = f;
547 }
548 if (isSupported(f = chrono.centuryOfEra())) {
549 centuryOfEra = f;
550 }
551 if (isSupported(f = chrono.era())) {
552 era = f;
553 }
554 }
555 }
556
557 private static boolean isSupported(DurationField field) {
558 return field == null ? false : field.isSupported();
559 }
560
561 private static boolean isSupported(DateTimeField field) {
562 return field == null ? false : field.isSupported();
563 }
564 }
565 }