1 16 package org.joda.time.chrono; 17 18 import java.util.Locale ; 19 20 import org.joda.time.Chronology; 21 import org.joda.time.DateTimeConstants; 22 import org.joda.time.DateTimeField; 23 import org.joda.time.DateTimeFieldType; 24 import org.joda.time.DateTimeZone; 25 import org.joda.time.DurationField; 26 import org.joda.time.DurationFieldType; 27 import org.joda.time.field.DividedDateTimeField; 28 import org.joda.time.field.FieldUtils; 29 import org.joda.time.field.MillisDurationField; 30 import org.joda.time.field.ZeroIsMaxDateTimeField; 31 import org.joda.time.field.OffsetDateTimeField; 32 import org.joda.time.field.PreciseDateTimeField; 33 import org.joda.time.field.PreciseDurationField; 34 import org.joda.time.field.RemainderDateTimeField; 35 36 50 abstract class BasicChronology extends AssembledChronology { 51 52 53 private static final long serialVersionUID = 8283225332206808863L; 54 55 private static final DurationField cMillisField; 56 private static final DurationField cSecondsField; 57 private static final DurationField cMinutesField; 58 private static final DurationField cHoursField; 59 private static final DurationField cHalfdaysField; 60 private static final DurationField cDaysField; 61 private static final DurationField cWeeksField; 62 63 private static final DateTimeField cMillisOfSecondField; 64 private static final DateTimeField cMillisOfDayField; 65 private static final DateTimeField cSecondOfMinuteField; 66 private static final DateTimeField cSecondOfDayField; 67 private static final DateTimeField cMinuteOfHourField; 68 private static final DateTimeField cMinuteOfDayField; 69 private static final DateTimeField cHourOfDayField; 70 private static final DateTimeField cHourOfHalfdayField; 71 private static final DateTimeField cClockhourOfDayField; 72 private static final DateTimeField cClockhourOfHalfdayField; 73 private static final DateTimeField cHalfdayOfDayField; 74 75 static { 76 cMillisField = MillisDurationField.INSTANCE; 77 cSecondsField = new PreciseDurationField 78 (DurationFieldType.seconds(), DateTimeConstants.MILLIS_PER_SECOND); 79 cMinutesField = new PreciseDurationField 80 (DurationFieldType.minutes(), DateTimeConstants.MILLIS_PER_MINUTE); 81 cHoursField = new PreciseDurationField 82 (DurationFieldType.hours(), DateTimeConstants.MILLIS_PER_HOUR); 83 cHalfdaysField = new PreciseDurationField 84 (DurationFieldType.halfdays(), DateTimeConstants.MILLIS_PER_DAY / 2); 85 cDaysField = new PreciseDurationField 86 (DurationFieldType.days(), DateTimeConstants.MILLIS_PER_DAY); 87 cWeeksField = new PreciseDurationField 88 (DurationFieldType.weeks(), DateTimeConstants.MILLIS_PER_WEEK); 89 90 cMillisOfSecondField = new PreciseDateTimeField 91 (DateTimeFieldType.millisOfSecond(), cMillisField, cSecondsField); 92 93 cMillisOfDayField = new PreciseDateTimeField 94 (DateTimeFieldType.millisOfDay(), cMillisField, cDaysField); 95 96 cSecondOfMinuteField = new PreciseDateTimeField 97 (DateTimeFieldType.secondOfMinute(), cSecondsField, cMinutesField); 98 99 cSecondOfDayField = new PreciseDateTimeField 100 (DateTimeFieldType.secondOfDay(), cSecondsField, cDaysField); 101 102 cMinuteOfHourField = new PreciseDateTimeField 103 (DateTimeFieldType.minuteOfHour(), cMinutesField, cHoursField); 104 105 cMinuteOfDayField = new PreciseDateTimeField 106 (DateTimeFieldType.minuteOfDay(), cMinutesField, cDaysField); 107 108 cHourOfDayField = new PreciseDateTimeField 109 (DateTimeFieldType.hourOfDay(), cHoursField, cDaysField); 110 111 cHourOfHalfdayField = new PreciseDateTimeField 112 (DateTimeFieldType.hourOfHalfday(), cHoursField, cHalfdaysField); 113 114 cClockhourOfDayField = new ZeroIsMaxDateTimeField 115 (cHourOfDayField, DateTimeFieldType.clockhourOfDay()); 116 117 cClockhourOfHalfdayField = new ZeroIsMaxDateTimeField 118 (cHourOfHalfdayField, DateTimeFieldType.clockhourOfHalfday()); 119 120 cHalfdayOfDayField = new HalfdayField(); 121 } 122 123 private static final int CACHE_SIZE = 1 << 10; 124 private static final int CACHE_MASK = CACHE_SIZE - 1; 125 126 private transient final YearInfo[] iYearInfoCache = new YearInfo[CACHE_SIZE]; 127 128 private final int iMinDaysInFirstWeek; 129 130 BasicChronology(Chronology base, Object param, int minDaysInFirstWeek) { 131 super(base, param); 132 133 if (minDaysInFirstWeek < 1 || minDaysInFirstWeek > 7) { 134 throw new IllegalArgumentException 135 ("Invalid min days in first week: " + minDaysInFirstWeek); 136 } 137 138 iMinDaysInFirstWeek = minDaysInFirstWeek; 139 } 140 141 public DateTimeZone getZone() { 142 Chronology base; 143 if ((base = getBase()) != null) { 144 return base.getZone(); 145 } 146 return DateTimeZone.UTC; 147 } 148 149 public long getDateTimeMillis( 150 int year, int monthOfYear, int dayOfMonth, int millisOfDay) 151 throws IllegalArgumentException { 152 Chronology base; 153 if ((base = getBase()) != null) { 154 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay); 155 } 156 157 FieldUtils.verifyValueBounds 158 (DateTimeFieldType.millisOfDay(), millisOfDay, 0, DateTimeConstants.MILLIS_PER_DAY); 159 return getDateMidnightMillis(year, monthOfYear, dayOfMonth) + millisOfDay; 160 } 161 162 public long getDateTimeMillis( 163 int year, int monthOfYear, int dayOfMonth, 164 int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond) 165 throws IllegalArgumentException { 166 Chronology base; 167 if ((base = getBase()) != null) { 168 return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, 169 hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond); 170 } 171 172 FieldUtils.verifyValueBounds(DateTimeFieldType.hourOfDay(), hourOfDay, 0, 23); 173 FieldUtils.verifyValueBounds(DateTimeFieldType.minuteOfHour(), minuteOfHour, 0, 59); 174 FieldUtils.verifyValueBounds(DateTimeFieldType.secondOfMinute(), secondOfMinute, 0, 59); 175 FieldUtils.verifyValueBounds(DateTimeFieldType.millisOfSecond(), millisOfSecond, 0, 999); 176 177 return getDateMidnightMillis(year, monthOfYear, dayOfMonth) 178 + hourOfDay * DateTimeConstants.MILLIS_PER_HOUR 179 + minuteOfHour * DateTimeConstants.MILLIS_PER_MINUTE 180 + secondOfMinute * DateTimeConstants.MILLIS_PER_SECOND 181 + millisOfSecond; 182 } 183 184 public int getMinimumDaysInFirstWeek() { 185 return iMinDaysInFirstWeek; 186 } 187 188 195 public String toString() { 196 StringBuffer sb = new StringBuffer (60); 197 String name = getClass().getName(); 198 int index = name.lastIndexOf('.'); 199 if (index >= 0) { 200 name = name.substring(index + 1); 201 } 202 sb.append(name); 203 sb.append('['); 204 DateTimeZone zone = getZone(); 205 if (zone != null) { 206 sb.append(zone.getID()); 207 } 208 if (getMinimumDaysInFirstWeek() != 4) { 209 sb.append(",mdfw="); 210 sb.append(getMinimumDaysInFirstWeek()); 211 } 212 sb.append(']'); 213 return sb.toString(); 214 } 215 216 protected void assemble(Fields fields) { 217 220 fields.millis = cMillisField; 221 fields.seconds = cSecondsField; 222 fields.minutes = cMinutesField; 223 fields.hours = cHoursField; 224 fields.halfdays = cHalfdaysField; 225 fields.days = cDaysField; 226 fields.weeks = cWeeksField; 227 228 fields.millisOfSecond = cMillisOfSecondField; 229 fields.millisOfDay = cMillisOfDayField; 230 fields.secondOfMinute = cSecondOfMinuteField; 231 fields.secondOfDay = cSecondOfDayField; 232 fields.minuteOfHour = cMinuteOfHourField; 233 fields.minuteOfDay = cMinuteOfDayField; 234 fields.hourOfDay = cHourOfDayField; 235 fields.hourOfHalfday = cHourOfHalfdayField; 236 fields.clockhourOfDay = cClockhourOfDayField; 237 fields.clockhourOfHalfday = cClockhourOfHalfdayField; 238 fields.halfdayOfDay = cHalfdayOfDayField; 239 240 243 fields.year = new BasicYearDateTimeField(this); 244 fields.yearOfEra = new GJYearOfEraDateTimeField(fields.year, this); 245 246 DateTimeField field = new OffsetDateTimeField( 248 fields.yearOfEra, 99); 249 fields.centuryOfEra = new DividedDateTimeField( 250 field, DateTimeFieldType.centuryOfEra(), 100); 251 252 field = new RemainderDateTimeField( 253 (DividedDateTimeField) fields.centuryOfEra); 254 fields.yearOfCentury = new OffsetDateTimeField( 255 field, DateTimeFieldType.yearOfCentury(), 1); 256 257 fields.era = new GJEraDateTimeField(this); 258 fields.dayOfWeek = new GJDayOfWeekDateTimeField(this, fields.days); 259 fields.dayOfMonth = new BasicDayOfMonthDateTimeField(this, fields.days); 260 fields.dayOfYear = new BasicDayOfYearDateTimeField(this, fields.days); 261 fields.monthOfYear = new GJMonthOfYearDateTimeField(this); 262 fields.weekyear = new BasicWeekyearDateTimeField(this); 263 fields.weekOfWeekyear = new BasicWeekOfWeekyearDateTimeField(this, fields.weeks); 264 265 field = new RemainderDateTimeField( 266 fields.weekyear, DateTimeFieldType.weekyearOfCentury(), 100); 267 fields.weekyearOfCentury = new OffsetDateTimeField( 268 field, DateTimeFieldType.weekyearOfCentury(), 1); 269 270 273 fields.years = fields.year.getDurationField(); 274 fields.centuries = fields.centuryOfEra.getDurationField(); 275 fields.months = fields.monthOfYear.getDurationField(); 276 fields.weekyears = fields.weekyear.getDurationField(); 277 } 278 279 285 int getDaysInYearMax() { 286 return 366; 287 } 288 289 295 int getDaysInYear(int year) { 296 return isLeapYear(year) ? 366 : 365; 297 } 298 299 305 int getWeeksInYear(int year) { 306 long firstWeekMillis1 = getFirstWeekOfYearMillis(year); 307 long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1); 308 return (int) ((firstWeekMillis2 - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK); 309 } 310 311 317 long getFirstWeekOfYearMillis(int year) { 318 long jan1millis = getYearMillis(year); 319 int jan1dayOfWeek = getDayOfWeek(jan1millis); 320 321 if (jan1dayOfWeek > (8 - iMinDaysInFirstWeek)) { 322 return jan1millis + (8 - jan1dayOfWeek) 324 * (long)DateTimeConstants.MILLIS_PER_DAY; 325 } else { 326 return jan1millis - (jan1dayOfWeek - 1) 328 * (long)DateTimeConstants.MILLIS_PER_DAY; 329 } 330 } 331 332 338 long getYearMillis(int year) { 339 return getYearInfo(year).iFirstDayMillis; 340 } 341 342 349 long getYearMonthMillis(int year, int month) { 350 long millis = getYearMillis(year); 351 millis += getTotalMillisByYearMonth(year, month); 352 return millis; 353 } 354 355 363 long getYearMonthDayMillis(int year, int month, int dayOfMonth) { 364 long millis = getYearMillis(year); 365 millis += getTotalMillisByYearMonth(year, month); 366 return millis + (dayOfMonth - 1) * (long)DateTimeConstants.MILLIS_PER_DAY; 367 } 368 369 372 int getYear(long instant) { 373 377 long unitMillis = getAverageMillisPerYearDividedByTwo(); 379 long i2 = (instant >> 1) + getApproxMillisAtEpochDividedByTwo(); 380 if (i2 < 0) { 381 i2 = i2 - unitMillis + 1; 382 } 383 int year = (int) (i2 / unitMillis); 384 385 long yearStart = getYearMillis(year); 386 long diff = instant - yearStart; 387 388 if (diff < 0) { 389 year--; 390 } else if (diff >= DateTimeConstants.MILLIS_PER_DAY * 365L) { 391 long oneYear; 393 if (isLeapYear(year)) { 394 oneYear = DateTimeConstants.MILLIS_PER_DAY * 366L; 395 } else { 396 oneYear = DateTimeConstants.MILLIS_PER_DAY * 365L; 397 } 398 399 yearStart += oneYear; 400 401 if (yearStart <= instant) { 402 year++; 404 } 405 } 406 407 return year; 408 } 409 410 413 int getMonthOfYear(long millis) { 414 return getMonthOfYear(millis, getYear(millis)); 415 } 416 417 421 abstract int getMonthOfYear(long millis, int year); 422 423 426 int getDayOfMonth(long millis) { 427 int year = getYear(millis); 428 int month = getMonthOfYear(millis, year); 429 return getDayOfMonth(millis, year, month); 430 } 431 432 436 int getDayOfMonth(long millis, int year) { 437 int month = getMonthOfYear(millis, year); 438 return getDayOfMonth(millis, year, month); 439 } 440 441 446 int getDayOfMonth(long millis, int year, int month) { 447 long dateMillis = getYearMillis(year); 448 dateMillis += getTotalMillisByYearMonth(year, month); 449 return (int) ((millis - dateMillis) / DateTimeConstants.MILLIS_PER_DAY) + 1; 450 } 451 452 455 int getDayOfYear(long instant) { 456 return getDayOfYear(instant, getYear(instant)); 457 } 458 459 463 int getDayOfYear(long instant, int year) { 464 long yearStart = getYearMillis(year); 465 return (int) ((instant - yearStart) / DateTimeConstants.MILLIS_PER_DAY) + 1; 466 } 467 468 471 int getWeekyear(long instant) { 472 int year = getYear(instant); 473 int week = getWeekOfWeekyear(instant, year); 474 if (week == 1) { 475 return getYear(instant + DateTimeConstants.MILLIS_PER_WEEK); 476 } else if (week > 51) { 477 return getYear(instant - (2 * DateTimeConstants.MILLIS_PER_WEEK)); 478 } else { 479 return year; 480 } 481 } 482 483 486 int getWeekOfWeekyear(long instant) { 487 return getWeekOfWeekyear(instant, getYear(instant)); 488 } 489 490 494 int getWeekOfWeekyear(long instant, int year) { 495 long firstWeekMillis1 = getFirstWeekOfYearMillis(year); 496 if (instant < firstWeekMillis1) { 497 return getWeeksInYear(year - 1); 498 } 499 long firstWeekMillis2 = getFirstWeekOfYearMillis(year + 1); 500 if (instant >= firstWeekMillis2) { 501 return 1; 502 } 503 return (int) ((instant - firstWeekMillis1) / DateTimeConstants.MILLIS_PER_WEEK) + 1; 504 } 505 506 509 int getDayOfWeek(long instant) { 510 512 long daysSince19700101; 513 if (instant >= 0) { 514 daysSince19700101 = instant / DateTimeConstants.MILLIS_PER_DAY; 515 } else { 516 daysSince19700101 = (instant - (DateTimeConstants.MILLIS_PER_DAY - 1)) 517 / DateTimeConstants.MILLIS_PER_DAY; 518 if (daysSince19700101 < -3) { 519 return 7 + (int) ((daysSince19700101 + 4) % 7); 520 } 521 } 522 523 return 1 + (int) ((daysSince19700101 + 3) % 7); 524 } 525 526 529 int getMillisOfDay(long instant) { 530 if (instant >= 0) { 531 return (int) (instant % DateTimeConstants.MILLIS_PER_DAY); 532 } else { 533 return (DateTimeConstants.MILLIS_PER_DAY - 1) 534 + (int) ((instant + 1) % DateTimeConstants.MILLIS_PER_DAY); 535 } 536 } 537 538 543 int getDaysInMonthMax() { 544 return 31; 545 } 546 547 553 int getDaysInMonthMax(long instant) { 554 int thisYear = getYear(instant); 555 int thisMonth = getMonthOfYear(instant, thisYear); 556 return getDaysInYearMonth(thisYear, thisMonth); 557 } 558 559 568 int getDaysInMonthMaxForSet(long instant, int value) { 569 return getDaysInMonthMax(instant); 570 } 571 572 581 long getDateMidnightMillis(int year, int monthOfYear, int dayOfMonth) { 582 FieldUtils.verifyValueBounds(DateTimeFieldType.year(), year, getMinYear(), getMaxYear()); 583 FieldUtils.verifyValueBounds(DateTimeFieldType.monthOfYear(), monthOfYear, 1, getMaxMonth(year)); 584 FieldUtils.verifyValueBounds(DateTimeFieldType.dayOfMonth(), dayOfMonth, 1, getDaysInYearMonth(year, monthOfYear)); 585 return getYearMonthDayMillis(year, monthOfYear, dayOfMonth); 586 } 587 588 595 abstract long getYearDifference(long minuendInstant, long subtrahendInstant); 596 597 603 abstract boolean isLeapYear(int year); 604 605 612 abstract int getDaysInYearMonth(int year, int month); 613 614 620 abstract int getDaysInMonthMax(int month); 621 622 630 abstract long getTotalMillisByYearMonth(int year, int month); 631 632 637 abstract long calculateFirstDayOfYearMillis(int year); 638 639 644 abstract int getMinYear(); 645 646 651 abstract int getMaxYear(); 652 653 660 int getMaxMonth(int year) { 661 return getMaxMonth(); 662 } 663 664 669 int getMaxMonth() { 670 return 12; 671 } 672 673 678 abstract long getAverageMillisPerYear(); 679 680 685 abstract long getAverageMillisPerYearDividedByTwo(); 686 687 692 abstract long getAverageMillisPerMonth(); 693 694 703 abstract long getApproxMillisAtEpochDividedByTwo(); 704 705 712 abstract long setYear(long instant, int year); 713 714 private YearInfo getYearInfo(int year) { 717 YearInfo info = iYearInfoCache[year & CACHE_MASK]; 718 if (info == null || info.iYear != year) { 719 info = new YearInfo(year, calculateFirstDayOfYearMillis(year)); 720 iYearInfoCache[year & CACHE_MASK] = info; 721 } 722 return info; 723 } 724 725 private static class HalfdayField extends PreciseDateTimeField { 726 private static final long serialVersionUID = 581601443656929254L; 727 728 HalfdayField() { 729 super(DateTimeFieldType.halfdayOfDay(), cHalfdaysField, cDaysField); 730 } 731 732 public String getAsText(int fieldValue, Locale locale) { 733 return GJLocaleSymbols.forLocale(locale).halfdayValueToText(fieldValue); 734 } 735 736 public long set(long millis, String text, Locale locale) { 737 return set(millis, GJLocaleSymbols.forLocale(locale).halfdayTextToValue(text)); 738 } 739 740 public int getMaximumTextLength(Locale locale) { 741 return GJLocaleSymbols.forLocale(locale).getHalfdayMaxTextLength(); 742 } 743 } 744 745 private static class YearInfo { 746 public final int iYear; 747 public final long iFirstDayMillis; 748 749 YearInfo(int year, long firstDayMillis) { 750 iYear = year; 751 iFirstDayMillis = firstDayMillis; 752 } 753 } 754 755 } 756 | Popular Tags |