1 16 package org.joda.time; 17 18 import java.io.Serializable ; 19 import java.util.ArrayList ; 20 import java.util.Arrays ; 21 import java.util.HashMap ; 22 import java.util.List ; 23 import java.util.Map ; 24 25 import org.joda.time.field.FieldUtils; 26 27 51 public class PeriodType implements Serializable { 52 53 private static final long serialVersionUID = 2274324892792009998L; 54 55 56 private static final Map cTypes = new HashMap (32); 57 58 static int YEAR_INDEX = 0; 59 static int MONTH_INDEX = 1; 60 static int WEEK_INDEX = 2; 61 static int DAY_INDEX = 3; 62 static int HOUR_INDEX = 4; 63 static int MINUTE_INDEX = 5; 64 static int SECOND_INDEX = 6; 65 static int MILLI_INDEX = 7; 66 67 private static PeriodType cStandard; 68 private static PeriodType cYMDTime; 69 private static PeriodType cYMD; 70 private static PeriodType cYWDTime; 71 private static PeriodType cYWD; 72 private static PeriodType cYDTime; 73 private static PeriodType cYD; 74 private static PeriodType cDTime; 75 private static PeriodType cTime; 76 77 private static PeriodType cYears; 78 private static PeriodType cMonths; 79 private static PeriodType cWeeks; 80 private static PeriodType cDays; 81 private static PeriodType cHours; 82 private static PeriodType cMinutes; 83 private static PeriodType cSeconds; 84 private static PeriodType cMillis; 85 86 101 public static PeriodType standard() { 102 PeriodType type = cStandard; 103 if (type == null) { 104 type = new PeriodType( 105 "Standard", 106 new DurationFieldType[] { 107 DurationFieldType.years(), DurationFieldType.months(), 108 DurationFieldType.weeks(), DurationFieldType.days(), 109 DurationFieldType.hours(), DurationFieldType.minutes(), 110 DurationFieldType.seconds(), DurationFieldType.millis(), 111 }, 112 new int[] { 0, 1, 2, 3, 4, 5, 6, 7, } 113 ); 114 cStandard = type; 115 } 116 return type; 117 } 118 119 133 public static PeriodType yearMonthDayTime() { 134 PeriodType type = cYMDTime; 135 if (type == null) { 136 type = new PeriodType( 137 "YearMonthDayTime", 138 new DurationFieldType[] { 139 DurationFieldType.years(), DurationFieldType.months(), 140 DurationFieldType.days(), 141 DurationFieldType.hours(), DurationFieldType.minutes(), 142 DurationFieldType.seconds(), DurationFieldType.millis(), 143 }, 144 new int[] { 0, 1, -1, 2, 3, 4, 5, 6, } 145 ); 146 cYMDTime = type; 147 } 148 return type; 149 } 150 151 162 public static PeriodType yearMonthDay() { 163 PeriodType type = cYMD; 164 if (type == null) { 165 type = new PeriodType( 166 "YearMonthDay", 167 new DurationFieldType[] { 168 DurationFieldType.years(), DurationFieldType.months(), 169 DurationFieldType.days(), 170 }, 171 new int[] { 0, 1, -1, 2, -1, -1, -1, -1, } 172 ); 173 cYMD = type; 174 } 175 return type; 176 } 177 178 192 public static PeriodType yearWeekDayTime() { 193 PeriodType type = cYWDTime; 194 if (type == null) { 195 type = new PeriodType( 196 "YearWeekDayTime", 197 new DurationFieldType[] { 198 DurationFieldType.years(), 199 DurationFieldType.weeks(), DurationFieldType.days(), 200 DurationFieldType.hours(), DurationFieldType.minutes(), 201 DurationFieldType.seconds(), DurationFieldType.millis(), 202 }, 203 new int[] { 0, -1, 1, 2, 3, 4, 5, 6, } 204 ); 205 cYWDTime = type; 206 } 207 return type; 208 } 209 210 221 public static PeriodType yearWeekDay() { 222 PeriodType type = cYWD; 223 if (type == null) { 224 type = new PeriodType( 225 "YearWeekDay", 226 new DurationFieldType[] { 227 DurationFieldType.years(), 228 DurationFieldType.weeks(), DurationFieldType.days(), 229 }, 230 new int[] { 0, -1, 1, 2, -1, -1, -1, -1, } 231 ); 232 cYWD = type; 233 } 234 return type; 235 } 236 237 250 public static PeriodType yearDayTime() { 251 PeriodType type = cYDTime; 252 if (type == null) { 253 type = new PeriodType( 254 "YearDayTime", 255 new DurationFieldType[] { 256 DurationFieldType.years(), DurationFieldType.days(), 257 DurationFieldType.hours(), DurationFieldType.minutes(), 258 DurationFieldType.seconds(), DurationFieldType.millis(), 259 }, 260 new int[] { 0, -1, -1, 1, 2, 3, 4, 5, } 261 ); 262 cYDTime = type; 263 } 264 return type; 265 } 266 267 277 public static PeriodType yearDay() { 278 PeriodType type = cYD; 279 if (type == null) { 280 type = new PeriodType( 281 "YearDay", 282 new DurationFieldType[] { 283 DurationFieldType.years(), DurationFieldType.days(), 284 }, 285 new int[] { 0, -1, -1, 1, -1, -1, -1, -1, } 286 ); 287 cYD = type; 288 } 289 return type; 290 } 291 292 304 public static PeriodType dayTime() { 305 PeriodType type = cDTime; 306 if (type == null) { 307 type = new PeriodType( 308 "DayTime", 309 new DurationFieldType[] { 310 DurationFieldType.days(), 311 DurationFieldType.hours(), DurationFieldType.minutes(), 312 DurationFieldType.seconds(), DurationFieldType.millis(), 313 }, 314 new int[] { -1, -1, -1, 0, 1, 2, 3, 4, } 315 ); 316 cDTime = type; 317 } 318 return type; 319 } 320 321 332 public static PeriodType time() { 333 PeriodType type = cTime; 334 if (type == null) { 335 type = new PeriodType( 336 "Time", 337 new DurationFieldType[] { 338 DurationFieldType.hours(), DurationFieldType.minutes(), 339 DurationFieldType.seconds(), DurationFieldType.millis(), 340 }, 341 new int[] { -1, -1, -1, -1, 0, 1, 2, 3, } 342 ); 343 cTime = type; 344 } 345 return type; 346 } 347 348 353 public static PeriodType years() { 354 PeriodType type = cYears; 355 if (type == null) { 356 type = new PeriodType( 357 "Years", 358 new DurationFieldType[] { DurationFieldType.years() }, 359 new int[] { 0, -1, -1, -1, -1, -1, -1, -1, } 360 ); 361 cYears = type; 362 } 363 return type; 364 } 365 366 371 public static PeriodType months() { 372 PeriodType type = cMonths; 373 if (type == null) { 374 type = new PeriodType( 375 "Months", 376 new DurationFieldType[] { DurationFieldType.months() }, 377 new int[] { -1, 0, -1, -1, -1, -1, -1, -1, } 378 ); 379 cMonths = type; 380 } 381 return type; 382 } 383 384 389 public static PeriodType weeks() { 390 PeriodType type = cWeeks; 391 if (type == null) { 392 type = new PeriodType( 393 "Weeks", 394 new DurationFieldType[] { DurationFieldType.weeks() }, 395 new int[] { -1, -1, 0, -1, -1, -1, -1, -1, } 396 ); 397 cWeeks = type; 398 } 399 return type; 400 } 401 402 407 public static PeriodType days() { 408 PeriodType type = cDays; 409 if (type == null) { 410 type = new PeriodType( 411 "Days", 412 new DurationFieldType[] { DurationFieldType.days() }, 413 new int[] { -1, -1, -1, 0, -1, -1, -1, -1, } 414 ); 415 cDays = type; 416 } 417 return type; 418 } 419 420 425 public static PeriodType hours() { 426 PeriodType type = cHours; 427 if (type == null) { 428 type = new PeriodType( 429 "Hours", 430 new DurationFieldType[] { DurationFieldType.hours() }, 431 new int[] { -1, -1, -1, -1, 0, -1, -1, -1, } 432 ); 433 cHours = type; 434 } 435 return type; 436 } 437 438 443 public static PeriodType minutes() { 444 PeriodType type = cMinutes; 445 if (type == null) { 446 type = new PeriodType( 447 "Minutes", 448 new DurationFieldType[] { DurationFieldType.minutes() }, 449 new int[] { -1, -1, -1, -1, -1, 0, -1, -1, } 450 ); 451 cMinutes = type; 452 } 453 return type; 454 } 455 456 461 public static PeriodType seconds() { 462 PeriodType type = cSeconds; 463 if (type == null) { 464 type = new PeriodType( 465 "Seconds", 466 new DurationFieldType[] { DurationFieldType.seconds() }, 467 new int[] { -1, -1, -1, -1, -1, -1, 0, -1, } 468 ); 469 cSeconds = type; 470 } 471 return type; 472 } 473 474 479 public static PeriodType millis() { 480 PeriodType type = cMillis; 481 if (type == null) { 482 type = new PeriodType( 483 "Millis", 484 new DurationFieldType[] { DurationFieldType.millis() }, 485 new int[] { -1, -1, -1, -1, -1, -1, -1, 0, } 486 ); 487 cMillis = type; 488 } 489 return type; 490 } 491 492 501 public static synchronized PeriodType forFields(DurationFieldType[] types) { 502 if (types == null || types.length == 0) { 503 throw new IllegalArgumentException ("Types array must not be null or empty"); 504 } 505 for (int i = 0; i < types.length; i++) { 506 if (types[i] == null) { 507 throw new IllegalArgumentException ("Types array must not contain null"); 508 } 509 } 510 Map cache = cTypes; 511 if (cTypes.isEmpty()) { 512 cache.put(standard(), standard()); 513 cache.put(yearMonthDayTime(), yearMonthDayTime()); 514 cache.put(yearMonthDay(), yearMonthDay()); 515 cache.put(yearWeekDayTime(), yearWeekDayTime()); 516 cache.put(yearWeekDay(), yearWeekDay()); 517 cache.put(yearDayTime(), yearDayTime()); 518 cache.put(yearDay(), yearDay()); 519 cache.put(dayTime(), dayTime()); 520 cache.put(time(), time()); 521 cache.put(years(), years()); 522 cache.put(months(), months()); 523 cache.put(weeks(), weeks()); 524 cache.put(days(), days()); 525 cache.put(hours(), hours()); 526 cache.put(minutes(), minutes()); 527 cache.put(seconds(), seconds()); 528 cache.put(millis(), millis()); 529 } 530 PeriodType inPartType = new PeriodType(null, types, null); 531 Object cached = cache.get(inPartType); 532 if (cached instanceof PeriodType) { 533 return (PeriodType) cached; 534 } 535 if (cached != null) { 536 throw new IllegalArgumentException ("PeriodType does not support fields: " + cached); 537 } 538 PeriodType type = standard(); 539 List list = new ArrayList (Arrays.asList(types)); 540 if (list.remove(DurationFieldType.years()) == false) { 541 type = type.withYearsRemoved(); 542 } 543 if (list.remove(DurationFieldType.months()) == false) { 544 type = type.withMonthsRemoved(); 545 } 546 if (list.remove(DurationFieldType.weeks()) == false) { 547 type = type.withWeeksRemoved(); 548 } 549 if (list.remove(DurationFieldType.days()) == false) { 550 type = type.withDaysRemoved(); 551 } 552 if (list.remove(DurationFieldType.hours()) == false) { 553 type = type.withHoursRemoved(); 554 } 555 if (list.remove(DurationFieldType.minutes()) == false) { 556 type = type.withMinutesRemoved(); 557 } 558 if (list.remove(DurationFieldType.seconds()) == false) { 559 type = type.withSecondsRemoved(); 560 } 561 if (list.remove(DurationFieldType.millis()) == false) { 562 type = type.withMillisRemoved(); 563 } 564 if (list.size() > 0) { 565 cache.put(inPartType, list); 566 throw new IllegalArgumentException ("PeriodType does not support fields: " + list); 567 } 568 PeriodType checkPartType = new PeriodType(null, type.iTypes, null); 570 PeriodType checkedType = (PeriodType) cache.get(checkPartType); 571 if (checkedType != null) { 572 cache.put(inPartType, checkedType); 573 return checkedType; 574 } 575 cache.put(inPartType, type); 576 return type; 577 } 578 579 581 private final String iName; 582 583 private final DurationFieldType[] iTypes; 584 585 private final int[] iIndices; 586 587 594 protected PeriodType(String name, DurationFieldType[] types, int[] indices) { 595 super(); 596 iName = name; 597 iTypes = types; 598 iIndices = indices; 599 } 600 601 607 public String getName() { 608 return iName; 609 } 610 611 616 public int size() { 617 return iTypes.length; 618 } 619 620 627 public DurationFieldType getFieldType(int index) { 628 return iTypes[index]; 629 } 630 631 637 public boolean isSupported(DurationFieldType type) { 638 return (indexOf(type) >= 0); 639 } 640 641 647 public int indexOf(DurationFieldType type) { 648 for (int i = 0, isize = size(); i < isize; i++) { 649 if (iTypes[i] == type) { 650 return i; 651 } 652 } 653 return -1; 654 } 655 656 661 public String toString() { 662 return "PeriodType[" + getName() + "]"; 663 } 664 665 673 int getIndexedField(ReadablePeriod period, int index) { 674 int realIndex = iIndices[index]; 675 return (realIndex == -1 ? 0 : period.getValue(realIndex)); 676 } 677 678 687 boolean setIndexedField(ReadablePeriod period, int index, int[] values, int newValue) { 688 int realIndex = iIndices[index]; 689 if (realIndex == -1) { 690 throw new IllegalArgumentException ("Field is not supported"); 691 } 692 values[realIndex] = newValue; 693 return true; 694 } 695 696 705 boolean addIndexedField(ReadablePeriod period, int index, int[] values, int valueToAdd) { 706 int realIndex = iIndices[index]; 707 if (realIndex == -1) { 708 throw new IllegalArgumentException ("Field is not supported"); 709 } 710 values[realIndex] = FieldUtils.safeAdd(values[realIndex], valueToAdd); 711 return true; 712 } 713 714 720 public PeriodType withYearsRemoved() { 721 return withFieldRemoved(0, "NoYears"); 722 } 723 724 729 public PeriodType withMonthsRemoved() { 730 return withFieldRemoved(1, "NoMonths"); 731 } 732 733 738 public PeriodType withWeeksRemoved() { 739 return withFieldRemoved(2, "NoWeeks"); 740 } 741 742 747 public PeriodType withDaysRemoved() { 748 return withFieldRemoved(3, "NoDays"); 749 } 750 751 756 public PeriodType withHoursRemoved() { 757 return withFieldRemoved(4, "NoHours"); 758 } 759 760 765 public PeriodType withMinutesRemoved() { 766 return withFieldRemoved(5, "NoMinutes"); 767 } 768 769 774 public PeriodType withSecondsRemoved() { 775 return withFieldRemoved(6, "NoSeconds"); 776 } 777 778 783 public PeriodType withMillisRemoved() { 784 return withFieldRemoved(7, "NoMillis"); 785 } 786 787 794 private PeriodType withFieldRemoved(int indicesIndex, String name) { 795 int fieldIndex = iIndices[indicesIndex]; 796 if (fieldIndex == -1) { 797 return this; 798 } 799 800 DurationFieldType[] types = new DurationFieldType[size() - 1]; 801 for (int i = 0; i < iTypes.length; i++) { 802 if (i < fieldIndex) { 803 types[i] = iTypes[i]; 804 } else if (i > fieldIndex) { 805 types[i - 1] = iTypes[i]; 806 } 807 } 808 809 int[] indices = new int[8]; 810 for (int i = 0; i < indices.length; i++) { 811 if (i < indicesIndex) { 812 indices[i] = iIndices[i]; 813 } else if (i > indicesIndex) { 814 indices[i] = (iIndices[i] == -1 ? -1 : iIndices[i] - 1); 815 } else { 816 indices[i] = -1; 817 } 818 } 819 return new PeriodType(getName() + name, types, indices); 820 } 821 822 830 public boolean equals(Object obj) { 831 if (this == obj) { 832 return true; 833 } 834 if (obj instanceof PeriodType == false) { 835 return false; 836 } 837 PeriodType other = (PeriodType) obj; 838 return (Arrays.equals(iTypes, other.iTypes)); 839 } 840 841 846 public int hashCode() { 847 int hash = 0; 848 for (int i = 0; i < iTypes.length; i++) { 849 hash += iTypes[i].hashCode(); 850 } 851 return hash; 852 } 853 854 } 855 | Popular Tags |