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.Serializable; 019 020 import org.joda.time.Chronology; 021 import org.joda.time.DateTimeField; 022 import org.joda.time.DateTimeFieldType; 023 import org.joda.time.DateTimeZone; 024 import org.joda.time.DurationField; 025 import org.joda.time.DurationFieldType; 026 import org.joda.time.IllegalFieldValueException; 027 import org.joda.time.ReadablePartial; 028 import org.joda.time.ReadablePeriod; 029 import org.joda.time.field.FieldUtils; 030 import org.joda.time.field.UnsupportedDateTimeField; 031 import org.joda.time.field.UnsupportedDurationField; 032 033 /** 034 * BaseChronology provides a skeleton implementation for chronology 035 * classes. Many utility methods are defined, but all fields are unsupported. 036 * <p> 037 * BaseChronology is thread-safe and immutable, and all subclasses must be 038 * as well. 039 * 040 * @author Brian S O'Neill 041 * @since 1.0 042 */ 043 public abstract class BaseChronology 044 extends Chronology 045 implements Serializable { 046 047 /** Serialization version. */ 048 private static final long serialVersionUID = -7310865996721419676L; 049 050 /** 051 * Restricted constructor. 052 */ 053 protected BaseChronology() { 054 super(); 055 } 056 057 /** 058 * Returns the DateTimeZone that this Chronology operates in, or null if 059 * unspecified. 060 * 061 * @return DateTimeZone null if unspecified 062 */ 063 public abstract DateTimeZone getZone(); 064 065 /** 066 * Returns an instance of this Chronology that operates in the UTC time 067 * zone. Chronologies that do not operate in a time zone or are already 068 * UTC must return themself. 069 * 070 * @return a version of this chronology that ignores time zones 071 */ 072 public abstract Chronology withUTC(); 073 074 /** 075 * Returns an instance of this Chronology that operates in any time zone. 076 * 077 * @return a version of this chronology with a specific time zone 078 * @param zone to use, or default if null 079 * @see org.joda.time.chrono.ZonedChronology 080 */ 081 public abstract Chronology withZone(DateTimeZone zone); 082 083 /** 084 * Returns a datetime millisecond instant, formed from the given year, 085 * month, day, and millisecond values. The set of given values must refer 086 * to a valid datetime, or else an IllegalArgumentException is thrown. 087 * <p> 088 * The default implementation calls upon separate DateTimeFields to 089 * determine the result. Subclasses are encouraged to provide a more 090 * efficient implementation. 091 * 092 * @param year year to use 093 * @param monthOfYear month to use 094 * @param dayOfMonth day of month to use 095 * @param millisOfDay millisecond to use 096 * @return millisecond instant from 1970-01-01T00:00:00Z 097 */ 098 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth, 099 int millisOfDay) 100 throws IllegalArgumentException 101 { 102 long instant = year().set(0, year); 103 instant = monthOfYear().set(instant, monthOfYear); 104 instant = dayOfMonth().set(instant, dayOfMonth); 105 return millisOfDay().set(instant, millisOfDay); 106 } 107 108 /** 109 * Returns a datetime millisecond instant, formed from the given year, 110 * month, day, hour, minute, second, and millisecond values. The set of 111 * given values must refer to a valid datetime, or else an 112 * IllegalArgumentException is thrown. 113 * <p> 114 * The default implementation calls upon separate DateTimeFields to 115 * determine the result. Subclasses are encouraged to provide a more 116 * efficient implementation. 117 * 118 * @param year year to use 119 * @param monthOfYear month to use 120 * @param dayOfMonth day of month to use 121 * @param hourOfDay hour to use 122 * @param minuteOfHour minute to use 123 * @param secondOfMinute second to use 124 * @param millisOfSecond millisecond to use 125 * @return millisecond instant from 1970-01-01T00:00:00Z 126 */ 127 public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth, 128 int hourOfDay, int minuteOfHour, 129 int secondOfMinute, int millisOfSecond) 130 throws IllegalArgumentException 131 { 132 long instant = year().set(0, year); 133 instant = monthOfYear().set(instant, monthOfYear); 134 instant = dayOfMonth().set(instant, dayOfMonth); 135 instant = hourOfDay().set(instant, hourOfDay); 136 instant = minuteOfHour().set(instant, minuteOfHour); 137 instant = secondOfMinute().set(instant, secondOfMinute); 138 return millisOfSecond().set(instant, millisOfSecond); 139 } 140 141 /** 142 * Returns a datetime millisecond instant, from from the given instant, 143 * hour, minute, second, and millisecond values. The set of given values 144 * must refer to a valid datetime, or else an IllegalArgumentException is 145 * thrown. 146 * <p> 147 * The default implementation calls upon separate DateTimeFields to 148 * determine the result. Subclasses are encouraged to provide a more 149 * efficient implementation. 150 * 151 * @param instant instant to start from 152 * @param hourOfDay hour to use 153 * @param minuteOfHour minute to use 154 * @param secondOfMinute second to use 155 * @param millisOfSecond millisecond to use 156 * @return millisecond instant from 1970-01-01T00:00:00Z 157 */ 158 public long getDateTimeMillis(long instant, 159 int hourOfDay, int minuteOfHour, 160 int secondOfMinute, int millisOfSecond) 161 throws IllegalArgumentException 162 { 163 instant = hourOfDay().set(instant, hourOfDay); 164 instant = minuteOfHour().set(instant, minuteOfHour); 165 instant = secondOfMinute().set(instant, secondOfMinute); 166 return millisOfSecond().set(instant, millisOfSecond); 167 } 168 169 //----------------------------------------------------------------------- 170 /** 171 * Validates whether the fields stored in a partial instant are valid. 172 * <p> 173 * This implementation uses {@link DateTimeField#getMinimumValue(ReadablePartial, int[])} 174 * and {@link DateTimeField#getMaximumValue(ReadablePartial, int[])}. 175 * 176 * @param partial the partial instant to validate 177 * @param values the values to validate, not null unless the partial is empty 178 * @throws IllegalArgumentException if the instant is invalid 179 */ 180 public void validate(ReadablePartial partial, int[] values) { 181 // check values in standard range, catching really stupid cases like -1 182 // this means that the second check will not hit trouble 183 int size = partial.size(); 184 for (int i = 0; i < size; i++) { 185 int value = values[i]; 186 DateTimeField field = partial.getField(i); 187 if (value < field.getMinimumValue()) { 188 throw new IllegalFieldValueException 189 (field.getType(), Integer.valueOf(value), 190 Integer.valueOf(field.getMinimumValue()), null); 191 } 192 if (value > field.getMaximumValue()) { 193 throw new IllegalFieldValueException 194 (field.getType(), Integer.valueOf(value), 195 null, Integer.valueOf(field.getMaximumValue())); 196 } 197 } 198 // check values in specific range, catching really odd cases like 30th Feb 199 for (int i = 0; i < size; i++) { 200 int value = values[i]; 201 DateTimeField field = partial.getField(i); 202 if (value < field.getMinimumValue(partial, values)) { 203 throw new IllegalFieldValueException 204 (field.getType(), Integer.valueOf(value), 205 Integer.valueOf(field.getMinimumValue(partial, values)), null); 206 } 207 if (value > field.getMaximumValue(partial, values)) { 208 throw new IllegalFieldValueException 209 (field.getType(), Integer.valueOf(value), 210 null, Integer.valueOf(field.getMaximumValue(partial, values))); 211 } 212 } 213 } 214 215 /** 216 * Gets the values of a partial from an instant. 217 * 218 * @param partial the partial instant to use 219 * @param instant the instant to query 220 * @return the values of the partial extracted from the instant 221 */ 222 public int[] get(ReadablePartial partial, long instant) { 223 int size = partial.size(); 224 int[] values = new int[size]; 225 for (int i = 0; i < size; i++) { 226 values[i] = partial.getFieldType(i).getField(this).get(instant); 227 } 228 return values; 229 } 230 231 /** 232 * Sets the partial into the instant. 233 * 234 * @param partial the partial instant to use 235 * @param instant the instant to update 236 * @return the updated instant 237 */ 238 public long set(ReadablePartial partial, long instant) { 239 for (int i = 0, isize = partial.size(); i < isize; i++) { 240 instant = partial.getFieldType(i).getField(this).set(instant, partial.getValue(i)); 241 } 242 return instant; 243 } 244 245 //----------------------------------------------------------------------- 246 /** 247 * Gets the values of a period from an interval. 248 * 249 * @param period the period instant to use 250 * @param startInstant the start instant of an interval to query 251 * @param endInstant the start instant of an interval to query 252 * @return the values of the period extracted from the interval 253 */ 254 public int[] get(ReadablePeriod period, long startInstant, long endInstant) { 255 int size = period.size(); 256 int[] values = new int[size]; 257 if (startInstant != endInstant) { 258 for (int i = 0; i < size; i++) { 259 DurationField field = period.getFieldType(i).getField(this); 260 int value = field.getDifference(endInstant, startInstant); 261 startInstant = field.add(startInstant, value); 262 values[i] = value; 263 } 264 } 265 return values; 266 } 267 268 /** 269 * Gets the values of a period from an interval. 270 * 271 * @param period the period instant to use 272 * @param duration the duration to query 273 * @return the values of the period extracted from the duration 274 */ 275 public int[] get(ReadablePeriod period, long duration) { 276 int size = period.size(); 277 int[] values = new int[size]; 278 if (duration != 0) { 279 long current = 0; 280 for (int i = 0; i < size; i++) { 281 DurationField field = period.getFieldType(i).getField(this); 282 if (field.isPrecise()) { 283 int value = field.getDifference(duration, current); 284 current = field.add(current, value); 285 values[i] = value; 286 } 287 } 288 } 289 return values; 290 } 291 292 /** 293 * Adds the period to the instant, specifying the number of times to add. 294 * 295 * @param period the period to add, null means add nothing 296 * @param instant the instant to add to 297 * @param scalar the number of times to add 298 * @return the updated instant 299 */ 300 public long add(ReadablePeriod period, long instant, int scalar) { 301 if (scalar != 0 && period != null) { 302 for (int i = 0, isize = period.size(); i < isize; i++) { 303 long value = period.getValue(i); // use long to allow for multiplication (fits OK) 304 if (value != 0) { 305 instant = period.getFieldType(i).getField(this).add(instant, value * scalar); 306 } 307 } 308 } 309 return instant; 310 } 311 312 //----------------------------------------------------------------------- 313 /** 314 * Adds the duration to the instant, specifying the number of times to add. 315 * 316 * @param instant the instant to add to 317 * @param duration the duration to add 318 * @param scalar the number of times to add 319 * @return the updated instant 320 */ 321 public long add(long instant, long duration, int scalar) { 322 if (duration == 0 || scalar == 0) { 323 return instant; 324 } 325 long add = FieldUtils.safeMultiply(duration, scalar); 326 return FieldUtils.safeAdd(instant, add); 327 } 328 329 // Millis 330 //----------------------------------------------------------------------- 331 /** 332 * Get the millis duration field for this chronology. 333 * 334 * @return DurationField or UnsupportedDurationField if unsupported 335 */ 336 public DurationField millis() { 337 return UnsupportedDurationField.getInstance(DurationFieldType.millis()); 338 } 339 340 /** 341 * Get the millis of second field for this chronology. 342 * 343 * @return DateTimeField or UnsupportedDateTimeField if unsupported 344 */ 345 public DateTimeField millisOfSecond() { 346 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.millisOfSecond(), millis()); 347 } 348 349 /** 350 * Get the millis of day field for this chronology. 351 * 352 * @return DateTimeField or UnsupportedDateTimeField if unsupported 353 */ 354 public DateTimeField millisOfDay() { 355 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.millisOfDay(), millis()); 356 } 357 358 // Second 359 //----------------------------------------------------------------------- 360 /** 361 * Get the seconds duration field for this chronology. 362 * 363 * @return DurationField or UnsupportedDurationField if unsupported 364 */ 365 public DurationField seconds() { 366 return UnsupportedDurationField.getInstance(DurationFieldType.seconds()); 367 } 368 369 /** 370 * Get the second of minute field for this chronology. 371 * 372 * @return DateTimeField or UnsupportedDateTimeField if unsupported 373 */ 374 public DateTimeField secondOfMinute() { 375 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.secondOfMinute(), seconds()); 376 } 377 378 /** 379 * Get the second of day field for this chronology. 380 * 381 * @return DateTimeField or UnsupportedDateTimeField if unsupported 382 */ 383 public DateTimeField secondOfDay() { 384 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.secondOfDay(), seconds()); 385 } 386 387 // Minute 388 //----------------------------------------------------------------------- 389 /** 390 * Get the minutes duration field for this chronology. 391 * 392 * @return DurationField or UnsupportedDurationField if unsupported 393 */ 394 public DurationField minutes() { 395 return UnsupportedDurationField.getInstance(DurationFieldType.minutes()); 396 } 397 398 /** 399 * Get the minute of hour field for this chronology. 400 * 401 * @return DateTimeField or UnsupportedDateTimeField if unsupported 402 */ 403 public DateTimeField minuteOfHour() { 404 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.minuteOfHour(), minutes()); 405 } 406 407 /** 408 * Get the minute of day field for this chronology. 409 * 410 * @return DateTimeField or UnsupportedDateTimeField if unsupported 411 */ 412 public DateTimeField minuteOfDay() { 413 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.minuteOfDay(), minutes()); 414 } 415 416 // Hour 417 //----------------------------------------------------------------------- 418 /** 419 * Get the hours duration field for this chronology. 420 * 421 * @return DurationField or UnsupportedDurationField if unsupported 422 */ 423 public DurationField hours() { 424 return UnsupportedDurationField.getInstance(DurationFieldType.hours()); 425 } 426 427 /** 428 * Get the hour of day (0-23) field for this chronology. 429 * 430 * @return DateTimeField or UnsupportedDateTimeField if unsupported 431 */ 432 public DateTimeField hourOfDay() { 433 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.hourOfDay(), hours()); 434 } 435 436 /** 437 * Get the hour of day (offset to 1-24) field for this chronology. 438 * 439 * @return DateTimeField or UnsupportedDateTimeField if unsupported 440 */ 441 public DateTimeField clockhourOfDay() { 442 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.clockhourOfDay(), hours()); 443 } 444 445 // Halfday 446 //----------------------------------------------------------------------- 447 /** 448 * Get the halfdays duration field for this chronology. 449 * 450 * @return DurationField or UnsupportedDurationField if unsupported 451 */ 452 public DurationField halfdays() { 453 return UnsupportedDurationField.getInstance(DurationFieldType.halfdays()); 454 } 455 456 /** 457 * Get the hour of am/pm (0-11) field for this chronology. 458 * 459 * @return DateTimeField or UnsupportedDateTimeField if unsupported 460 */ 461 public DateTimeField hourOfHalfday() { 462 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.hourOfHalfday(), hours()); 463 } 464 465 /** 466 * Get the hour of am/pm (offset to 1-12) field for this chronology. 467 * 468 * @return DateTimeField or UnsupportedDateTimeField if unsupported 469 */ 470 public DateTimeField clockhourOfHalfday() { 471 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.clockhourOfHalfday(), hours()); 472 } 473 474 /** 475 * Get the AM(0) PM(1) field for this chronology. 476 * 477 * @return DateTimeField or UnsupportedDateTimeField if unsupported 478 */ 479 public DateTimeField halfdayOfDay() { 480 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.halfdayOfDay(), halfdays()); 481 } 482 483 // Day 484 //----------------------------------------------------------------------- 485 /** 486 * Get the days duration field for this chronology. 487 * 488 * @return DurationField or UnsupportedDurationField if unsupported 489 */ 490 public DurationField days() { 491 return UnsupportedDurationField.getInstance(DurationFieldType.days()); 492 } 493 494 /** 495 * Get the day of week field for this chronology. 496 * 497 * <p>DayOfWeek values are defined in 498 * {@link org.joda.time.DateTimeConstants DateTimeConstants}. 499 * They use the ISO definitions, where 1 is Monday and 7 is Sunday. 500 * 501 * @return DateTimeField or UnsupportedDateTimeField if unsupported 502 */ 503 public DateTimeField dayOfWeek() { 504 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfWeek(), days()); 505 } 506 507 /** 508 * Get the day of month field for this chronology. 509 * 510 * @return DateTimeField or UnsupportedDateTimeField if unsupported 511 */ 512 public DateTimeField dayOfMonth() { 513 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfMonth(), days()); 514 } 515 516 /** 517 * Get the day of year field for this chronology. 518 * 519 * @return DateTimeField or UnsupportedDateTimeField if unsupported 520 */ 521 public DateTimeField dayOfYear() { 522 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.dayOfYear(), days()); 523 } 524 525 // Week 526 //----------------------------------------------------------------------- 527 /** 528 * Get the weeks duration field for this chronology. 529 * 530 * @return DurationField or UnsupportedDurationField if unsupported 531 */ 532 public DurationField weeks() { 533 return UnsupportedDurationField.getInstance(DurationFieldType.weeks()); 534 } 535 536 /** 537 * Get the week of a week based year field for this chronology. 538 * 539 * @return DateTimeField or UnsupportedDateTimeField if unsupported 540 */ 541 public DateTimeField weekOfWeekyear() { 542 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekOfWeekyear(), weeks()); 543 } 544 545 // Weekyear 546 //----------------------------------------------------------------------- 547 /** 548 * Get the weekyears duration field for this chronology. 549 * 550 * @return DurationField or UnsupportedDurationField if unsupported 551 */ 552 public DurationField weekyears() { 553 return UnsupportedDurationField.getInstance(DurationFieldType.weekyears()); 554 } 555 556 /** 557 * Get the year of a week based year field for this chronology. 558 * 559 * @return DateTimeField or UnsupportedDateTimeField if unsupported 560 */ 561 public DateTimeField weekyear() { 562 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekyear(), weekyears()); 563 } 564 565 /** 566 * Get the year of a week based year in a century field for this chronology. 567 * 568 * @return DateTimeField or UnsupportedDateTimeField if unsupported 569 */ 570 public DateTimeField weekyearOfCentury() { 571 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.weekyearOfCentury(), weekyears()); 572 } 573 574 // Month 575 //----------------------------------------------------------------------- 576 /** 577 * Get the months duration field for this chronology. 578 * 579 * @return DurationField or UnsupportedDurationField if unsupported 580 */ 581 public DurationField months() { 582 return UnsupportedDurationField.getInstance(DurationFieldType.months()); 583 } 584 585 /** 586 * Get the month of year field for this chronology. 587 * 588 * @return DateTimeField or UnsupportedDateTimeField if unsupported 589 */ 590 public DateTimeField monthOfYear() { 591 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.monthOfYear(), months()); 592 } 593 594 // Year 595 //----------------------------------------------------------------------- 596 /** 597 * Get the years duration field for this chronology. 598 * 599 * @return DurationField or UnsupportedDurationField if unsupported 600 */ 601 public DurationField years() { 602 return UnsupportedDurationField.getInstance(DurationFieldType.years()); 603 } 604 605 /** 606 * Get the year field for this chronology. 607 * 608 * @return DateTimeField or UnsupportedDateTimeField if unsupported 609 */ 610 public DateTimeField year() { 611 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.year(), years()); 612 } 613 614 /** 615 * Get the year of era field for this chronology. 616 * 617 * @return DateTimeField or UnsupportedDateTimeField if unsupported 618 */ 619 public DateTimeField yearOfEra() { 620 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.yearOfEra(), years()); 621 } 622 623 /** 624 * Get the year of century field for this chronology. 625 * 626 * @return DateTimeField or UnsupportedDateTimeField if unsupported 627 */ 628 public DateTimeField yearOfCentury() { 629 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.yearOfCentury(), years()); 630 } 631 632 // Century 633 //----------------------------------------------------------------------- 634 /** 635 * Get the centuries duration field for this chronology. 636 * 637 * @return DurationField or UnsupportedDurationField if unsupported 638 */ 639 public DurationField centuries() { 640 return UnsupportedDurationField.getInstance(DurationFieldType.centuries()); 641 } 642 643 /** 644 * Get the century of era field for this chronology. 645 * 646 * @return DateTimeField or UnsupportedDateTimeField if unsupported 647 */ 648 public DateTimeField centuryOfEra() { 649 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.centuryOfEra(), centuries()); 650 } 651 652 // Era 653 //----------------------------------------------------------------------- 654 /** 655 * Get the eras duration field for this chronology. 656 * 657 * @return DurationField or UnsupportedDurationField if unsupported 658 */ 659 public DurationField eras() { 660 return UnsupportedDurationField.getInstance(DurationFieldType.eras()); 661 } 662 663 /** 664 * Get the era field for this chronology. 665 * 666 * @return DateTimeField or UnsupportedDateTimeField if unsupported 667 */ 668 public DateTimeField era() { 669 return UnsupportedDateTimeField.getInstance(DateTimeFieldType.era(), eras()); 670 } 671 672 //----------------------------------------------------------------------- 673 /** 674 * Gets a debugging toString. 675 * 676 * @return a debugging string 677 */ 678 public abstract String toString(); 679 680 }