1 16 17 package org.apache.xerces.jaxp.datatype; 18 19 import java.io.IOException ; 20 import java.io.ObjectStreamException ; 21 import java.io.Serializable ; 22 import java.math.BigDecimal ; 23 import java.math.BigInteger ; 24 import java.util.Calendar ; 25 import java.util.Date ; 26 import java.util.GregorianCalendar ; 27 28 import javax.xml.datatype.DatatypeConstants ; 29 import javax.xml.datatype.Duration ; 30 import javax.xml.datatype.XMLGregorianCalendar ; 31 32 import org.apache.xerces.util.DatatypeMessageFormatter; 33 34 99 class DurationImpl 100 extends Duration 101 implements Serializable { 102 103 106 private static final int FIELD_NUM = 6; 107 108 111 private static final DatatypeConstants.Field [] FIELDS = new DatatypeConstants.Field []{ 112 DatatypeConstants.YEARS, 113 DatatypeConstants.MONTHS, 114 DatatypeConstants.DAYS, 115 DatatypeConstants.HOURS, 116 DatatypeConstants.MINUTES, 117 DatatypeConstants.SECONDS 118 }; 119 120 123 private static final int[] FIELD_IDS = { 124 DatatypeConstants.YEARS.getId(), 125 DatatypeConstants.MONTHS.getId(), 126 DatatypeConstants.DAYS.getId(), 127 DatatypeConstants.HOURS.getId(), 128 DatatypeConstants.MINUTES.getId(), 129 DatatypeConstants.SECONDS.getId() 130 }; 131 132 135 private static final BigDecimal ZERO = BigDecimal.valueOf((long) 0); 136 137 141 private final int signum; 142 143 146 private final BigInteger years; 147 148 151 private final BigInteger months; 152 153 156 private final BigInteger days; 157 158 161 private final BigInteger hours; 162 163 166 private final BigInteger minutes; 167 168 171 private final BigDecimal seconds; 172 173 180 public int getSign() { 181 182 return signum; 183 } 184 185 191 private int calcSignum(boolean isPositive) { 192 if ((years == null || years.signum() == 0) 193 && (months == null || months.signum() == 0) 194 && (days == null || days.signum() == 0) 195 && (hours == null || hours.signum() == 0) 196 && (minutes == null || minutes.signum() == 0) 197 && (seconds == null || seconds.signum() == 0)) { 198 return 0; 199 } 200 201 if (isPositive) { 202 return 1; 203 } else { 204 return -1; 205 } 206 207 } 208 209 229 protected DurationImpl( 230 boolean isPositive, 231 BigInteger years, 232 BigInteger months, 233 BigInteger days, 234 BigInteger hours, 235 BigInteger minutes, 236 BigDecimal seconds) { 237 238 this.years = years; 239 this.months = months; 240 this.days = days; 241 this.hours = hours; 242 this.minutes = minutes; 243 this.seconds = seconds; 244 245 this.signum = calcSignum(isPositive); 246 247 if (years == null 249 && months == null 250 && days == null 251 && hours == null 252 && minutes == null 253 && seconds == null) { 254 throw new IllegalArgumentException ( 255 DatatypeMessageFormatter.formatMessage(null, "AllFieldsNull", null) 257 ); 258 } 259 testNonNegative(years, DatatypeConstants.YEARS); 260 testNonNegative(months, DatatypeConstants.MONTHS); 261 testNonNegative(days, DatatypeConstants.DAYS); 262 testNonNegative(hours, DatatypeConstants.HOURS); 263 testNonNegative(minutes, DatatypeConstants.MINUTES); 264 testNonNegative(seconds, DatatypeConstants.SECONDS); 265 } 266 267 274 private static void testNonNegative(BigInteger n, DatatypeConstants.Field f) { 275 if (n != null && n.signum() < 0) { 276 throw new IllegalArgumentException ( 277 DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object []{f.toString()}) 278 ); 279 } 280 } 281 282 289 private static void testNonNegative(BigDecimal n, DatatypeConstants.Field f) { 290 if (n != null && n.signum() < 0) { 291 292 throw new IllegalArgumentException ( 293 DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object []{f.toString()}) 294 ); 295 } 296 } 297 298 311 protected DurationImpl( 312 final boolean isPositive, 313 final int years, 314 final int months, 315 final int days, 316 final int hours, 317 final int minutes, 318 final int seconds) { 319 this( 320 isPositive, 321 wrap(years), 322 wrap(months), 323 wrap(days), 324 wrap(hours), 325 wrap(minutes), 326 seconds != 0 ? new BigDecimal (String.valueOf(seconds)) : null); 327 } 328 329 336 private static BigInteger wrap(final int i) { 337 338 if (i == DatatypeConstants.FIELD_UNDEFINED) { 340 return null; 341 } 342 343 return new BigInteger (String.valueOf(i)); 345 } 346 347 364 protected DurationImpl(final long durationInMilliSeconds) { 365 366 boolean is0x8000000000000000L = false; 367 long l = durationInMilliSeconds; 368 369 if (l > 0) { 370 signum = 1; 371 } else if (l < 0) { 372 signum = -1; 373 if (l == 0x8000000000000000L) { 374 l++; 376 is0x8000000000000000L = true; 377 } 378 l *= -1; 379 } else { 380 signum = 0; 381 } 382 383 this.years = null; 384 this.months = null; 385 386 this.seconds = 387 BigDecimal.valueOf((l % 60000L) + (is0x8000000000000000L ? 1 : 0), 3); 388 389 l /= 60000L; 390 this.minutes = (l == 0) ? null : BigInteger.valueOf(l % 60L); 391 392 l /= 60L; 393 this.hours = (l == 0) ? null : BigInteger.valueOf(l % 24L); 394 395 l /= 24L; 396 this.days = (l == 0) ? null : BigInteger.valueOf(l); 397 } 398 399 400 431 protected DurationImpl(String lexicalRepresentation) 432 throws IllegalArgumentException { 433 435 final String s = lexicalRepresentation; 436 boolean positive; 437 int[] idx = new int[1]; 438 int length = s.length(); 439 boolean timeRequired = false; 440 441 if (lexicalRepresentation == null) { 442 throw new NullPointerException (); 443 } 444 445 idx[0] = 0; 446 if (length != idx[0] && s.charAt(idx[0]) == '-') { 447 idx[0]++; 448 positive = false; 449 } else { 450 positive = true; 451 } 452 453 if (length != idx[0] && s.charAt(idx[0]++) != 'P') { 454 throw new IllegalArgumentException (s); } 456 457 458 int dateLen = 0; 462 String [] dateParts = new String [3]; 463 int[] datePartsIndex = new int[3]; 464 while (length != idx[0] 465 && isDigit(s.charAt(idx[0])) 466 && dateLen < 3) { 467 datePartsIndex[dateLen] = idx[0]; 468 dateParts[dateLen++] = parsePiece(s, idx); 469 } 470 471 if (length != idx[0]) { 472 if (s.charAt(idx[0]++) == 'T') { 473 timeRequired = true; 474 } else { 475 throw new IllegalArgumentException (s); } 477 } 478 479 int timeLen = 0; 480 String [] timeParts = new String [3]; 481 int[] timePartsIndex = new int[3]; 482 while (length != idx[0] 483 && isDigitOrPeriod(s.charAt(idx[0])) 484 && timeLen < 3) { 485 timePartsIndex[timeLen] = idx[0]; 486 timeParts[timeLen++] = parsePiece(s, idx); 487 } 488 489 if (timeRequired && timeLen == 0) { 490 throw new IllegalArgumentException (s); } 492 493 if (length != idx[0]) { 494 throw new IllegalArgumentException (s); } 496 if (dateLen == 0 && timeLen == 0) { 497 throw new IllegalArgumentException (s); } 499 500 organizeParts(s, dateParts, datePartsIndex, dateLen, "YMD"); 503 organizeParts(s, timeParts, timePartsIndex, timeLen, "HMS"); 504 505 years = parseBigInteger(s, dateParts[0], datePartsIndex[0]); 507 months = parseBigInteger(s, dateParts[1], datePartsIndex[1]); 508 days = parseBigInteger(s, dateParts[2], datePartsIndex[2]); 509 hours = parseBigInteger(s, timeParts[0], timePartsIndex[0]); 510 minutes = parseBigInteger(s, timeParts[1], timePartsIndex[1]); 511 seconds = parseBigDecimal(s, timeParts[2], timePartsIndex[2]); 512 signum = calcSignum(positive); 513 } 514 515 516 523 private static boolean isDigit(char ch) { 524 return '0' <= ch && ch <= '9'; 525 } 526 527 534 private static boolean isDigitOrPeriod(char ch) { 535 return isDigit(ch) || ch == '.'; 536 } 537 538 548 private static String parsePiece(String whole, int[] idx) 549 throws IllegalArgumentException { 550 int start = idx[0]; 551 while (idx[0] < whole.length() 552 && isDigitOrPeriod(whole.charAt(idx[0]))) { 553 idx[0]++; 554 } 555 if (idx[0] == whole.length()) { 556 throw new IllegalArgumentException (whole); } 558 559 idx[0]++; 560 561 return whole.substring(start, idx[0]); 562 } 563 564 575 private static void organizeParts( 576 String whole, 577 String [] parts, 578 int[] partsIndex, 579 int len, 580 String tokens) 581 throws IllegalArgumentException { 582 583 int idx = tokens.length(); 584 for (int i = len - 1; i >= 0; i--) { 585 int nidx = 586 tokens.lastIndexOf( 587 parts[i].charAt(parts[i].length() - 1), 588 idx - 1); 589 if (nidx == -1) { 590 throw new IllegalArgumentException (whole); 591 } 593 594 for (int j = nidx + 1; j < idx; j++) { 595 parts[j] = null; 596 } 597 idx = nidx; 598 parts[idx] = parts[i]; 599 partsIndex[idx] = partsIndex[i]; 600 } 601 for (idx--; idx >= 0; idx--) { 602 parts[idx] = null; 603 } 604 } 605 606 617 private static BigInteger parseBigInteger( 618 String whole, 619 String part, 620 int index) 621 throws IllegalArgumentException { 622 if (part == null) { 623 return null; 624 } 625 part = part.substring(0, part.length() - 1); 626 return new BigInteger (part); 628 } 632 633 644 private static BigDecimal parseBigDecimal( 645 String whole, 646 String part, 647 int index) 648 throws IllegalArgumentException { 649 if (part == null) { 650 return null; 651 } 652 part = part.substring(0, part.length() - 1); 653 return new BigDecimal (part); 656 } 660 661 664 private static final XMLGregorianCalendar [] TEST_POINTS = new XMLGregorianCalendar [] { 665 XMLGregorianCalendarImpl.parse("1696-09-01T00:00:00Z"), 666 XMLGregorianCalendarImpl.parse("1697-02-01T00:00:00Z"), 667 XMLGregorianCalendarImpl.parse("1903-03-01T00:00:00Z"), 668 XMLGregorianCalendarImpl.parse("1903-07-01T00:00:00Z") 669 }; 670 671 701 public int compare(Duration rhs) { 702 703 BigInteger maxintAsBigInteger = BigInteger.valueOf((long) Integer.MAX_VALUE); 704 BigInteger minintAsBigInteger = BigInteger.valueOf((long) Integer.MIN_VALUE); 705 706 if (years != null && years.compareTo(maxintAsBigInteger) == 1) { 708 throw new UnsupportedOperationException ( 709 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 710 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), years.toString()}) 711 ); 715 } 716 if (months != null && months.compareTo(maxintAsBigInteger) == 1) { 717 throw new UnsupportedOperationException ( 718 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 719 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), months.toString()}) 720 721 ); 725 } 726 if (days != null && days.compareTo(maxintAsBigInteger) == 1) { 727 throw new UnsupportedOperationException ( 728 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 729 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), days.toString()}) 730 731 ); 735 } 736 if (hours != null && hours.compareTo(maxintAsBigInteger) == 1) { 737 throw new UnsupportedOperationException ( 738 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 739 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), hours.toString()}) 740 741 ); 745 } 746 if (minutes != null && minutes.compareTo(maxintAsBigInteger) == 1) { 747 throw new UnsupportedOperationException ( 748 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 749 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), minutes.toString()}) 750 751 ); 755 } 756 if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) { 757 throw new UnsupportedOperationException ( 758 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 759 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), seconds.toString()}) 760 761 ); 765 } 766 767 BigInteger rhsYears = (BigInteger ) rhs.getField(DatatypeConstants.YEARS); 769 if (rhsYears != null && rhsYears.compareTo(maxintAsBigInteger) == 1) { 770 throw new UnsupportedOperationException ( 771 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 772 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), rhsYears.toString()}) 773 774 ); 778 } 779 BigInteger rhsMonths = (BigInteger ) rhs.getField(DatatypeConstants.MONTHS); 780 if (rhsMonths != null && rhsMonths.compareTo(maxintAsBigInteger) == 1) { 781 throw new UnsupportedOperationException ( 782 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 783 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), rhsMonths.toString()}) 784 785 ); 789 } 790 BigInteger rhsDays = (BigInteger ) rhs.getField(DatatypeConstants.DAYS); 791 if (rhsDays != null && rhsDays.compareTo(maxintAsBigInteger) == 1) { 792 throw new UnsupportedOperationException ( 793 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 794 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), rhsDays.toString()}) 795 796 ); 800 } 801 BigInteger rhsHours = (BigInteger ) rhs.getField(DatatypeConstants.HOURS); 802 if (rhsHours != null && rhsHours.compareTo(maxintAsBigInteger) == 1) { 803 throw new UnsupportedOperationException ( 804 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 805 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), rhsHours.toString()}) 806 807 ); 811 } 812 BigInteger rhsMinutes = (BigInteger ) rhs.getField(DatatypeConstants.MINUTES); 813 if (rhsMinutes != null && rhsMinutes.compareTo(maxintAsBigInteger) == 1) { 814 throw new UnsupportedOperationException ( 815 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 816 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), rhsMinutes.toString()}) 817 818 ); 822 } 823 BigDecimal rhsSecondsAsBigDecimal = (BigDecimal ) rhs.getField(DatatypeConstants.SECONDS); 824 BigInteger rhsSeconds = null; 825 if ( rhsSecondsAsBigDecimal != null ) { 826 rhsSeconds = rhsSecondsAsBigDecimal.toBigInteger(); 827 } 828 if (rhsSeconds != null && rhsSeconds.compareTo(maxintAsBigInteger) == 1) { 829 throw new UnsupportedOperationException ( 830 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 831 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), rhsSeconds.toString()}) 832 833 ); 837 } 838 839 GregorianCalendar lhsCalendar = new GregorianCalendar ( 841 1970, 842 1, 843 1, 844 0, 845 0, 846 0); 847 lhsCalendar.add(GregorianCalendar.YEAR, getYears() * getSign()); 848 lhsCalendar.add(GregorianCalendar.MONTH, getMonths() * getSign()); 849 lhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, getDays() * getSign()); 850 lhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, getHours() * getSign()); 851 lhsCalendar.add(GregorianCalendar.MINUTE, getMinutes() * getSign()); 852 lhsCalendar.add(GregorianCalendar.SECOND, getSeconds() * getSign()); 853 854 GregorianCalendar rhsCalendar = new GregorianCalendar ( 856 1970, 857 1, 858 1, 859 0, 860 0, 861 0); 862 rhsCalendar.add(GregorianCalendar.YEAR, rhs.getYears() * rhs.getSign()); 863 rhsCalendar.add(GregorianCalendar.MONTH, rhs.getMonths() * rhs.getSign()); 864 rhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, rhs.getDays() * rhs.getSign()); 865 rhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, rhs.getHours() * rhs.getSign()); 866 rhsCalendar.add(GregorianCalendar.MINUTE, rhs.getMinutes() * rhs.getSign()); 867 rhsCalendar.add(GregorianCalendar.SECOND, rhs.getSeconds() * rhs.getSign()); 868 869 870 if (lhsCalendar.equals(rhsCalendar)) { 871 return DatatypeConstants.EQUAL; 872 } 873 874 return compareDates(this, rhs); 875 } 876 877 889 private int compareDates(Duration duration1, Duration duration2) { 890 891 int resultA = DatatypeConstants.INDETERMINATE; 892 int resultB = DatatypeConstants.INDETERMINATE; 893 894 XMLGregorianCalendar tempA = (XMLGregorianCalendar )TEST_POINTS[0].clone(); 895 XMLGregorianCalendar tempB = (XMLGregorianCalendar )TEST_POINTS[0].clone(); 896 897 tempA.add(duration1); 899 tempB.add(duration2); 900 resultA = tempA.compare(tempB); 901 if ( resultA == DatatypeConstants.INDETERMINATE ) { 902 return DatatypeConstants.INDETERMINATE; 903 } 904 905 tempA = (XMLGregorianCalendar )TEST_POINTS[1].clone(); 906 tempB = (XMLGregorianCalendar )TEST_POINTS[1].clone(); 907 908 tempA.add(duration1); 909 tempB.add(duration2); 910 resultB = tempA.compare(tempB); 911 resultA = compareResults(resultA, resultB); 912 if (resultA == DatatypeConstants.INDETERMINATE) { 913 return DatatypeConstants.INDETERMINATE; 914 } 915 916 tempA = (XMLGregorianCalendar )TEST_POINTS[2].clone(); 917 tempB = (XMLGregorianCalendar )TEST_POINTS[2].clone(); 918 919 tempA.add(duration1); 920 tempB.add(duration2); 921 resultB = tempA.compare(tempB); 922 resultA = compareResults(resultA, resultB); 923 if (resultA == DatatypeConstants.INDETERMINATE) { 924 return DatatypeConstants.INDETERMINATE; 925 } 926 927 tempA = (XMLGregorianCalendar )TEST_POINTS[3].clone(); 928 tempB = (XMLGregorianCalendar )TEST_POINTS[3].clone(); 929 930 tempA.add(duration1); 931 tempB.add(duration2); 932 resultB = tempA.compare(tempB); 933 resultA = compareResults(resultA, resultB); 934 935 return resultA; 936 } 937 938 private int compareResults(int resultA, int resultB){ 939 940 if ( resultB == DatatypeConstants.INDETERMINATE ) { 941 return DatatypeConstants.INDETERMINATE; 942 } 943 else if ( resultA!=resultB) { 944 return DatatypeConstants.INDETERMINATE; 945 } 946 return resultA; 947 } 948 949 954 public int hashCode() { 955 Calendar cal = TEST_POINTS[0].toGregorianCalendar(); 957 this.addTo(cal); 958 return (int) getCalendarTimeInMillis(cal); 959 } 960 961 980 public String toString() { 981 StringBuffer buf = new StringBuffer (); 982 if (signum < 0) { 983 buf.append('-'); 984 } 985 buf.append('P'); 986 987 if (years != null) { 988 buf.append(years + "Y"); 989 } 990 if (months != null) { 991 buf.append(months + "M"); 992 } 993 if (days != null) { 994 buf.append(days + "D"); 995 } 996 997 if (hours != null || minutes != null || seconds != null) { 998 buf.append('T'); 999 if (hours != null) { 1000 buf.append(hours + "H"); 1001 } 1002 if (minutes != null) { 1003 buf.append(minutes + "M"); 1004 } 1005 if (seconds != null) { 1006 buf.append(toString(seconds) + "S"); 1007 } 1008 } 1009 1010 return buf.toString(); 1011 } 1012 1013 1023 private String toString(BigDecimal bd) { 1024 String intString = bd.unscaledValue().toString(); 1025 int scale = bd.scale(); 1026 1027 if (scale == 0) { 1028 return intString; 1029 } 1030 1031 1032 StringBuffer buf; 1033 int insertionPoint = intString.length() - scale; 1034 if (insertionPoint == 0) { 1035 return "0." + intString; 1036 } else if (insertionPoint > 0) { 1037 buf = new StringBuffer (intString); 1038 buf.insert(insertionPoint, '.'); 1039 } else { 1040 buf = new StringBuffer (3 - insertionPoint + intString.length()); 1041 buf.append("0."); 1042 for (int i = 0; i < -insertionPoint; i++) { 1043 buf.append('0'); 1044 } 1045 buf.append(intString); 1046 } 1047 return buf.toString(); 1048 } 1049 1050 1065 public boolean isSet(DatatypeConstants.Field field) { 1066 1067 if (field == null) { 1068 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)" ; 1069 throw new NullPointerException ( 1070 DatatypeMessageFormatter.formatMessage(null, "FieldCannotBeNull", new Object []{methodName}) 1072 ); 1073 } 1074 1075 if (field == DatatypeConstants.YEARS) { 1076 return years != null; 1077 } 1078 1079 if (field == DatatypeConstants.MONTHS) { 1080 return months != null; 1081 } 1082 1083 if (field == DatatypeConstants.DAYS) { 1084 return days != null; 1085 } 1086 1087 if (field == DatatypeConstants.HOURS) { 1088 return hours != null; 1089 } 1090 1091 if (field == DatatypeConstants.MINUTES) { 1092 return minutes != null; 1093 } 1094 1095 if (field == DatatypeConstants.SECONDS) { 1096 return seconds != null; 1097 } 1098 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)"; 1099 1100 throw new IllegalArgumentException ( 1101 DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object []{methodName, field.toString()}) 1102 ); 1103 1104 } 1105 1106 1130 public Number getField(DatatypeConstants.Field field) { 1131 1132 if (field == null) { 1133 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field) " ; 1134 1135 throw new NullPointerException ( 1136 DatatypeMessageFormatter.formatMessage(null,"FieldCannotBeNull", new Object []{methodName}) 1137 ); 1138 } 1139 1140 if (field == DatatypeConstants.YEARS) { 1141 return years; 1142 } 1143 1144 if (field == DatatypeConstants.MONTHS) { 1145 return months; 1146 } 1147 1148 if (field == DatatypeConstants.DAYS) { 1149 return days; 1150 } 1151 1152 if (field == DatatypeConstants.HOURS) { 1153 return hours; 1154 } 1155 1156 if (field == DatatypeConstants.MINUTES) { 1157 return minutes; 1158 } 1159 1160 if (field == DatatypeConstants.SECONDS) { 1161 return seconds; 1162 } 1163 1170 String methodName = "javax.xml.datatype.Duration" + "#(getSet(DatatypeConstants.Field field)"; 1171 1172 throw new IllegalArgumentException ( 1173 DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object []{methodName, field.toString()}) 1174 ); 1175 1176 } 1177 1178 1197 public int getYears() { 1198 return getInt(DatatypeConstants.YEARS); 1199 } 1200 1201 1210 public int getMonths() { 1211 return getInt(DatatypeConstants.MONTHS); 1212 } 1213 1214 1223 public int getDays() { 1224 return getInt(DatatypeConstants.DAYS); 1225 } 1226 1227 1237 public int getHours() { 1238 return getInt(DatatypeConstants.HOURS); 1239 } 1240 1241 1251 public int getMinutes() { 1252 return getInt(DatatypeConstants.MINUTES); 1253 } 1254 1255 1266 public int getSeconds() { 1267 return getInt(DatatypeConstants.SECONDS); 1268 } 1269 1270 1279 private int getInt(DatatypeConstants.Field field) { 1280 Number n = getField(field); 1281 if (n == null) { 1282 return 0; 1283 } else { 1284 return n.intValue(); 1285 } 1286 } 1287 1288 1318 public long getTimeInMillis(final Calendar startInstant) { 1319 Calendar cal = (Calendar ) startInstant.clone(); 1320 addTo(cal); 1321 return getCalendarTimeInMillis(cal) 1322 - getCalendarTimeInMillis(startInstant); 1323 } 1324 1325 1356 public long getTimeInMillis(final Date startInstant) { 1357 Calendar cal = new GregorianCalendar (); 1358 cal.setTime(startInstant); 1359 this.addTo(cal); 1360 return getCalendarTimeInMillis(cal) - startInstant.getTime(); 1361 } 1362 1363 1387 1417 public Duration normalizeWith(Calendar startTimeInstant) { 1418 1419 Calendar c = (Calendar ) startTimeInstant.clone(); 1420 1421 c.add(Calendar.YEAR, getYears() * signum); 1424 c.add(Calendar.MONTH, getMonths() * signum); 1425 c.add(Calendar.DAY_OF_MONTH, getDays() * signum); 1426 1427 long diff = getCalendarTimeInMillis(c) - getCalendarTimeInMillis(startTimeInstant); 1429 int days = (int) (diff / (1000L * 60L * 60L * 24L)); 1430 1431 return new DurationImpl( 1432 days >= 0, 1433 null, 1434 null, 1435 wrap(Math.abs(days)), 1436 (BigInteger ) getField(DatatypeConstants.HOURS), 1437 (BigInteger ) getField(DatatypeConstants.MINUTES), 1438 (BigDecimal ) getField(DatatypeConstants.SECONDS)); 1439 } 1440 1441 1457 public Duration multiply(int factor) { 1458 return multiply(BigDecimal.valueOf(factor)); 1459 } 1460 1461 1508 public Duration multiply(BigDecimal factor) { 1509 BigDecimal carry = ZERO; 1510 int factorSign = factor.signum(); 1511 factor = factor.abs(); 1512 1513 BigDecimal [] buf = new BigDecimal [6]; 1514 1515 for (int i = 0; i < 5; i++) { 1516 BigDecimal bd = getFieldAsBigDecimal(FIELDS[i]); 1517 bd = bd.multiply(factor).add(carry); 1518 1519 buf[i] = bd.setScale(0, BigDecimal.ROUND_DOWN); 1520 1521 bd = bd.subtract(buf[i]); 1522 if (i == 1) { 1523 if (bd.signum() != 0) { 1524 throw new IllegalStateException (); } else { 1526 carry = ZERO; 1527 } 1528 } else { 1529 carry = bd.multiply(FACTORS[i]); 1530 } 1531 } 1532 1533 if (seconds != null) { 1534 buf[5] = seconds.multiply(factor).add(carry); 1535 } else { 1536 buf[5] = carry; 1537 } 1538 1539 return new DurationImpl( 1540 this.signum * factorSign >= 0, 1541 toBigInteger(buf[0], null == years), 1542 toBigInteger(buf[1], null == months), 1543 toBigInteger(buf[2], null == days), 1544 toBigInteger(buf[3], null == hours), 1545 toBigInteger(buf[4], null == minutes), 1546 (buf[5].signum() == 0 && seconds == null) ? null : buf[5]); 1547 } 1548 1549 1558 private BigDecimal getFieldAsBigDecimal(DatatypeConstants.Field f) { 1559 if (f == DatatypeConstants.SECONDS) { 1560 if (seconds != null) { 1561 return seconds; 1562 } else { 1563 return ZERO; 1564 } 1565 } else { 1566 BigInteger bi = (BigInteger ) getField(f); 1567 if (bi == null) { 1568 return ZERO; 1569 } else { 1570 return new BigDecimal (bi); 1571 } 1572 } 1573 } 1574 1575 1583 private static BigInteger toBigInteger( 1584 BigDecimal value, 1585 boolean canBeNull) { 1586 if (canBeNull && value.signum() == 0) { 1587 return null; 1588 } else { 1589 return value.unscaledValue(); 1590 } 1591 } 1592 1593 1597 private static final BigDecimal [] FACTORS = new BigDecimal []{ 1598 BigDecimal.valueOf(12), 1599 null, 1600 BigDecimal.valueOf(24), 1601 BigDecimal.valueOf(60), 1602 BigDecimal.valueOf(60) 1603 }; 1604 1605 1655 public Duration add(final Duration rhs) { 1656 Duration lhs = this; 1657 BigDecimal [] buf = new BigDecimal [6]; 1658 1659 buf[0] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.YEARS), 1660 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.YEARS), rhs.getSign())); 1661 buf[1] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.MONTHS), 1662 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.MONTHS), rhs.getSign())); 1663 buf[2] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.DAYS), 1664 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.DAYS), rhs.getSign())); 1665 buf[3] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.HOURS), 1666 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.HOURS), rhs.getSign())); 1667 buf[4] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.MINUTES), 1668 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.MINUTES), rhs.getSign())); 1669 buf[5] = sanitize((BigDecimal ) lhs.getField(DatatypeConstants.SECONDS), 1670 lhs.getSign()).add(sanitize((BigDecimal ) rhs.getField(DatatypeConstants.SECONDS), rhs.getSign())); 1671 1672 alignSigns(buf, 0, 2); alignSigns(buf, 2, 6); 1676 int s = 0; 1678 for (int i = 0; i < 6; i++) { 1679 if (s * buf[i].signum() < 0) { 1680 throw new IllegalStateException (); 1681 } 1682 if (s == 0) { 1683 s = buf[i].signum(); 1684 } 1685 } 1686 1687 return new DurationImpl( 1688 s >= 0, 1689 toBigInteger(sanitize(buf[0], s), 1690 lhs.getField(DatatypeConstants.YEARS) == null && rhs.getField(DatatypeConstants.YEARS) == null), 1691 toBigInteger(sanitize(buf[1], s), 1692 lhs.getField(DatatypeConstants.MONTHS) == null && rhs.getField(DatatypeConstants.MONTHS) == null), 1693 toBigInteger(sanitize(buf[2], s), 1694 lhs.getField(DatatypeConstants.DAYS) == null && rhs.getField(DatatypeConstants.DAYS) == null), 1695 toBigInteger(sanitize(buf[3], s), 1696 lhs.getField(DatatypeConstants.HOURS) == null && rhs.getField(DatatypeConstants.HOURS) == null), 1697 toBigInteger(sanitize(buf[4], s), 1698 lhs.getField(DatatypeConstants.MINUTES) == null && rhs.getField(DatatypeConstants.MINUTES) == null), 1699 (buf[5].signum() == 0 1700 && lhs.getField(DatatypeConstants.SECONDS) == null 1701 && rhs.getField(DatatypeConstants.SECONDS) == null) ? null : sanitize(buf[5], s)); 1702 } 1703 1704 private static void alignSigns(BigDecimal [] buf, int start, int end) { 1705 boolean touched; 1707 1708 do { touched = false; 1710 int s = 0; 1712 for (int i = start; i < end; i++) { 1713 if (s * buf[i].signum() < 0) { 1714 touched = true; 1716 1717 BigDecimal borrow = 1719 buf[i].abs().divide( 1720 FACTORS[i - 1], 1721 BigDecimal.ROUND_UP); 1722 if (buf[i].signum() > 0) { 1723 borrow = borrow.negate(); 1724 } 1725 1726 buf[i - 1] = buf[i - 1].subtract(borrow); 1728 buf[i] = buf[i].add(borrow.multiply(FACTORS[i - 1])); 1729 } 1730 if (buf[i].signum() != 0) { 1731 s = buf[i].signum(); 1732 } 1733 } 1734 } while (touched); 1735 } 1736 1737 1745 private static BigDecimal sanitize(BigInteger value, int signum) { 1746 if (signum == 0 || value == null) { 1747 return ZERO; 1748 } 1749 if (signum > 0) { 1750 return new BigDecimal (value); 1751 } 1752 return new BigDecimal (value.negate()); 1753 } 1754 1755 1763 static BigDecimal sanitize(BigDecimal value, int signum) { 1764 if (signum == 0 || value == null) { 1765 return ZERO; 1766 } 1767 if (signum > 0) { 1768 return value; 1769 } 1770 return value.negate(); 1771 } 1772 1773 1822 public Duration subtract(final Duration rhs) { 1823 return add(rhs.negate()); 1824 } 1825 1826 1838 public Duration negate() { 1839 return new DurationImpl( 1840 signum <= 0, 1841 years, 1842 months, 1843 days, 1844 hours, 1845 minutes, 1846 seconds); 1847 } 1848 1849 1856 public int signum() { 1857 return signum; 1858 } 1859 1860 1861 1900 public void addTo(Calendar calendar) { 1901 calendar.add(Calendar.YEAR, getYears() * signum); 1902 calendar.add(Calendar.MONTH, getMonths() * signum); 1903 calendar.add(Calendar.DAY_OF_MONTH, getDays() * signum); 1904 calendar.add(Calendar.HOUR, getHours() * signum); 1905 calendar.add(Calendar.MINUTE, getMinutes() * signum); 1906 calendar.add(Calendar.SECOND, getSeconds() * signum); 1907 1908 if (seconds != null) { 1909 BigDecimal fraction = 1910 seconds.subtract(seconds.setScale(0, BigDecimal.ROUND_DOWN)); 1911 int millisec = fraction.movePointRight(3).intValue(); 1912 calendar.add(Calendar.MILLISECOND, millisec * signum); 1913 } 1914 } 1915 1916 1937 public void addTo(Date date) { 1938 Calendar cal = new GregorianCalendar (); 1939 cal.setTime(date); this.addTo(cal); 1941 date.setTime(getCalendarTimeInMillis(cal)); 1942 } 1943 1944 1950 private static final long serialVersionUID = 1L; 1951 1952 1960 private Object writeReplace() throws IOException { 1961 return new DurationStream(this.toString()); 1962 } 1963 1964 1969 private static class DurationStream implements Serializable { 1970 private final String lexical; 1971 1972 private DurationStream(String _lexical) { 1973 this.lexical = _lexical; 1974 } 1975 1976 private Object readResolve() throws ObjectStreamException { 1977 return new DurationImpl(lexical); 1979 } 1983 1984 private static final long serialVersionUID = 1L; 1985 } 1986 1987 1995 private static long getCalendarTimeInMillis(Calendar cal) { 1996 return cal.getTime().getTime(); 1997 } 1998} 1999 2000 | Popular Tags |