| 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.chrono; |
| 17 | |
| 18 | import java.io.IOException; |
| 19 | import java.io.ObjectInputStream; |
| 20 | |
| 21 | import org.joda.time.Chronology; |
| 22 | import org.joda.time.DateTimeField; |
| 23 | import org.joda.time.DateTimeZone; |
| 24 | import org.joda.time.DurationField; |
| 25 | |
| 26 | /** |
| 27 | * Abstract Chronology that enables chronologies to be assembled from |
| 28 | * a container of fields. |
| 29 | * <p> |
| 30 | * AssembledChronology is thread-safe and immutable. |
| 31 | * |
| 32 | * @author Brian S O'Neill |
| 33 | * @since 1.0 |
| 34 | */ |
| 35 | public abstract class AssembledChronology extends BaseChronology { |
| 36 | |
| 37 | private static final long serialVersionUID = -6728465968995518215L; |
| 38 | |
| 39 | private final Chronology iBase; |
| 40 | private final Object iParam; |
| 41 | |
| 42 | private transient DurationField iMillis; |
| 43 | private transient DurationField iSeconds; |
| 44 | private transient DurationField iMinutes; |
| 45 | private transient DurationField iHours; |
| 46 | private transient DurationField iHalfdays; |
| 47 | |
| 48 | private transient DurationField iDays; |
| 49 | private transient DurationField iWeeks; |
| 50 | private transient DurationField iWeekyears; |
| 51 | private transient DurationField iMonths; |
| 52 | private transient DurationField iYears; |
| 53 | private transient DurationField iCenturies; |
| 54 | private transient DurationField iEras; |
| 55 | |
| 56 | private transient DateTimeField iMillisOfSecond; |
| 57 | private transient DateTimeField iMillisOfDay; |
| 58 | private transient DateTimeField iSecondOfMinute; |
| 59 | private transient DateTimeField iSecondOfDay; |
| 60 | private transient DateTimeField iMinuteOfHour; |
| 61 | private transient DateTimeField iMinuteOfDay; |
| 62 | private transient DateTimeField iHourOfDay; |
| 63 | private transient DateTimeField iClockhourOfDay; |
| 64 | private transient DateTimeField iHourOfHalfday; |
| 65 | private transient DateTimeField iClockhourOfHalfday; |
| 66 | private transient DateTimeField iHalfdayOfDay; |
| 67 | |
| 68 | private transient DateTimeField iDayOfWeek; |
| 69 | private transient DateTimeField iDayOfMonth; |
| 70 | private transient DateTimeField iDayOfYear; |
| 71 | private transient DateTimeField iWeekOfWeekyear; |
| 72 | private transient DateTimeField iWeekyear; |
| 73 | private transient DateTimeField iWeekyearOfCentury; |
| 74 | private transient DateTimeField iMonthOfYear; |
| 75 | private transient DateTimeField iYear; |
| 76 | private transient DateTimeField iYearOfEra; |
| 77 | private transient DateTimeField iYearOfCentury; |
| 78 | private transient DateTimeField iCenturyOfEra; |
| 79 | private transient DateTimeField iEra; |
| 80 | |
| 81 | // Bit set determines which base fields are used |
| 82 | // bit 1 set: hourOfDay, minuteOfHour, secondOfMinute, and millisOfSecond fields |
| 83 | // bit 2 set: millisOfDayField |
| 84 | // bit 3 set: year, monthOfYear, and dayOfMonth fields |
| 85 | private transient int iBaseFlags; |
| 86 | |
| 87 | /** |
| 88 | * Constructor calls the assemble method, enabling subclasses to define its |
| 89 | * supported fields. If a base chronology is supplied, the field set |
| 90 | * initially contains references to each base chronology field. |
| 91 | * <p> |
| 92 | * Other methods in this class will delegate to the base chronology, if it |
| 93 | * can be determined that the base chronology will produce the same results |
| 94 | * as AbstractChronology. |
| 95 | * |
| 96 | * @param base optional base chronology to copy initial fields from |
| 97 | * @param param optional param object avalable for assemble method |
| 98 | */ |
| 99 | 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 | } |