1 3 9 10 package com.sun.org.apache.xerces.internal.jaxp.datatype; 11 12 import java.io.IOException ; 13 import java.io.ObjectStreamException ; 14 import java.io.Serializable ; 15 import java.math.BigDecimal ; 16 import java.math.BigInteger ; 17 import java.util.Calendar ; 18 import java.util.Date ; 19 import java.util.GregorianCalendar ; 20 21 import javax.xml.datatype.DatatypeConstants ; 22 import javax.xml.datatype.Duration ; 23 import javax.xml.datatype.XMLGregorianCalendar ; 24 import javax.xml.namespace.QName ; 25 import com.sun.org.apache.xerces.internal.util.DatatypeMessageFormatter; 26 27 94 public class DurationImpl 95 extends Duration  96 implements Serializable { 97 98 101 private static final int FIELD_NUM = 6; 102 103 106 private static final DatatypeConstants.Field [] FIELDS = new DatatypeConstants.Field []{ 107 DatatypeConstants.YEARS, 108 DatatypeConstants.MONTHS, 109 DatatypeConstants.DAYS, 110 DatatypeConstants.HOURS, 111 DatatypeConstants.MINUTES, 112 DatatypeConstants.SECONDS 113 }; 114 115 118 private static final int[] FIELD_IDS = { 119 DatatypeConstants.YEARS.getId(), 120 DatatypeConstants.MONTHS.getId(), 121 DatatypeConstants.DAYS.getId(), 122 DatatypeConstants.HOURS.getId(), 123 DatatypeConstants.MINUTES.getId(), 124 DatatypeConstants.SECONDS.getId() 125 }; 126 127 130 private static final BigDecimal ZERO = BigDecimal.valueOf((long) 0); 131 132 136 private final int signum; 137 138 141 private final BigInteger years; 142 143 146 private final BigInteger months; 147 148 151 private final BigInteger days; 152 153 156 private final BigInteger hours; 157 158 161 private final BigInteger minutes; 162 163 166 private final BigDecimal seconds; 167 168 175 public int getSign() { 176 177 return signum; 178 } 179 180 186 private int calcSignum(boolean isPositive) { 187 if ((years == null || years.signum() == 0) 188 && (months == null || months.signum() == 0) 189 && (days == null || days.signum() == 0) 190 && (hours == null || hours.signum() == 0) 191 && (minutes == null || minutes.signum() == 0) 192 && (seconds == null || seconds.signum() == 0)) { 193 return 0; 194 } 195 196 if (isPositive) { 197 return 1; 198 } else { 199 return -1; 200 } 201 202 } 203 204 224 protected DurationImpl( 225 boolean isPositive, 226 BigInteger years, 227 BigInteger months, 228 BigInteger days, 229 BigInteger hours, 230 BigInteger minutes, 231 BigDecimal seconds) { 232 233 this.years = years; 234 this.months = months; 235 this.days = days; 236 this.hours = hours; 237 this.minutes = minutes; 238 this.seconds = seconds; 239 240 this.signum = calcSignum(isPositive); 241 242 if (years == null 244 && months == null 245 && days == null 246 && hours == null 247 && minutes == null 248 && seconds == null) { 249 throw new IllegalArgumentException ( 250 DatatypeMessageFormatter.formatMessage(null, "AllFieldsNull", null) 252 ); 253 } 254 testNonNegative(years, DatatypeConstants.YEARS); 255 testNonNegative(months, DatatypeConstants.MONTHS); 256 testNonNegative(days, DatatypeConstants.DAYS); 257 testNonNegative(hours, DatatypeConstants.HOURS); 258 testNonNegative(minutes, DatatypeConstants.MINUTES); 259 testNonNegative(seconds, DatatypeConstants.SECONDS); 260 } 261 262 269 private static void testNonNegative(BigInteger n, DatatypeConstants.Field f) { 270 if (n != null && n.signum() < 0) { 271 throw new IllegalArgumentException ( 272 DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object []{f.toString()}) 273 ); 274 } 275 } 276 277 284 private static void testNonNegative(BigDecimal n, DatatypeConstants.Field f) { 285 if (n != null && n.signum() < 0) { 286 287 throw new IllegalArgumentException ( 288 DatatypeMessageFormatter.formatMessage(null, "NegativeField", new Object []{f.toString()}) 289 ); 290 } 291 } 292 293 306 protected DurationImpl( 307 final boolean isPositive, 308 final int years, 309 final int months, 310 final int days, 311 final int hours, 312 final int minutes, 313 final int seconds) { 314 this( 315 isPositive, 316 wrap(years), 317 wrap(months), 318 wrap(days), 319 wrap(hours), 320 wrap(minutes), 321 seconds != 0 ? new BigDecimal (String.valueOf(seconds)) : null); 322 } 323 324 331 private static BigInteger wrap(final int i) { 332 333 if (i == DatatypeConstants.FIELD_UNDEFINED) { 335 return null; 336 } 337 338 return new BigInteger (String.valueOf(i)); 340 } 341 342 359 protected DurationImpl(final long durationInMilliSeconds) { 360 361 boolean is0x8000000000000000L = false; 362 long l = durationInMilliSeconds; 363 364 if (l > 0) { 365 signum = 1; 366 } else if (l < 0) { 367 signum = -1; 368 if (l == 0x8000000000000000L) { 369 l++; 371 is0x8000000000000000L = true; 372 } 373 l *= -1; 374 } else { 375 signum = 0; 376 } 377 378 this.years = null; 379 this.months = null; 380 381 this.seconds = 382 BigDecimal.valueOf((l % 60000L) + (is0x8000000000000000L ? 1 : 0), 3); 383 384 l /= 60000L; 385 this.minutes = (l == 0) ? null : BigInteger.valueOf(l % 60L); 386 387 l /= 60L; 388 this.hours = (l == 0) ? null : BigInteger.valueOf(l % 24L); 389 390 l /= 24L; 391 this.days = (l == 0) ? null : BigInteger.valueOf(l); 392 } 393 394 395 426 protected DurationImpl(String lexicalRepresentation) 427 throws IllegalArgumentException { 428 430 final String s = lexicalRepresentation; 431 boolean positive; 432 int[] idx = new int[1]; 433 int length = s.length(); 434 boolean timeRequired = false; 435 436 if (lexicalRepresentation == null) { 437 throw new NullPointerException (); 438 } 439 440 idx[0] = 0; 441 if (length != idx[0] && s.charAt(idx[0]) == '-') { 442 idx[0]++; 443 positive = false; 444 } else { 445 positive = true; 446 } 447 448 if (length != idx[0] && s.charAt(idx[0]++) != 'P') { 449 throw new IllegalArgumentException (s); } 451 452 453 int dateLen = 0; 457 String [] dateParts = new String [3]; 458 int[] datePartsIndex = new int[3]; 459 while (length != idx[0] 460 && isDigit(s.charAt(idx[0])) 461 && dateLen < 3) { 462 datePartsIndex[dateLen] = idx[0]; 463 dateParts[dateLen++] = parsePiece(s, idx); 464 } 465 466 if (length != idx[0]) { 467 if (s.charAt(idx[0]++) == 'T') { 468 timeRequired = true; 469 } else { 470 throw new IllegalArgumentException (s); } 472 } 473 474 int timeLen = 0; 475 String [] timeParts = new String [3]; 476 int[] timePartsIndex = new int[3]; 477 while (length != idx[0] 478 && isDigitOrPeriod(s.charAt(idx[0])) 479 && timeLen < 3) { 480 timePartsIndex[timeLen] = idx[0]; 481 timeParts[timeLen++] = parsePiece(s, idx); 482 } 483 484 if (timeRequired && timeLen == 0) { 485 throw new IllegalArgumentException (s); } 487 488 if (length != idx[0]) { 489 throw new IllegalArgumentException (s); } 491 if (dateLen == 0 && timeLen == 0) { 492 throw new IllegalArgumentException (s); } 494 495 organizeParts(s, dateParts, datePartsIndex, dateLen, "YMD"); 498 organizeParts(s, timeParts, timePartsIndex, timeLen, "HMS"); 499 500 years = parseBigInteger(s, dateParts[0], datePartsIndex[0]); 502 months = parseBigInteger(s, dateParts[1], datePartsIndex[1]); 503 days = parseBigInteger(s, dateParts[2], datePartsIndex[2]); 504 hours = parseBigInteger(s, timeParts[0], timePartsIndex[0]); 505 minutes = parseBigInteger(s, timeParts[1], timePartsIndex[1]); 506 seconds = parseBigDecimal(s, timeParts[2], timePartsIndex[2]); 507 signum = calcSignum(positive); 508 } 509 510 511 518 private static boolean isDigit(char ch) { 519 return '0' <= ch && ch <= '9'; 520 } 521 522 529 private static boolean isDigitOrPeriod(char ch) { 530 return isDigit(ch) || ch == '.'; 531 } 532 533 543 private static String parsePiece(String whole, int[] idx) 544 throws IllegalArgumentException { 545 int start = idx[0]; 546 while (idx[0] < whole.length() 547 && isDigitOrPeriod(whole.charAt(idx[0]))) { 548 idx[0]++; 549 } 550 if (idx[0] == whole.length()) { 551 throw new IllegalArgumentException (whole); } 553 554 idx[0]++; 555 556 return whole.substring(start, idx[0]); 557 } 558 559 570 private static void organizeParts( 571 String whole, 572 String [] parts, 573 int[] partsIndex, 574 int len, 575 String tokens) 576 throws IllegalArgumentException { 577 578 int idx = tokens.length(); 579 for (int i = len - 1; i >= 0; i--) { 580 int nidx = 581 tokens.lastIndexOf( 582 parts[i].charAt(parts[i].length() - 1), 583 idx - 1); 584 if (nidx == -1) { 585 throw new IllegalArgumentException (whole); 586 } 588 589 for (int j = nidx + 1; j < idx; j++) { 590 parts[j] = null; 591 } 592 idx = nidx; 593 parts[idx] = parts[i]; 594 partsIndex[idx] = partsIndex[i]; 595 } 596 for (idx--; idx >= 0; idx--) { 597 parts[idx] = null; 598 } 599 } 600 601 612 private static BigInteger parseBigInteger( 613 String whole, 614 String part, 615 int index) 616 throws IllegalArgumentException { 617 if (part == null) { 618 return null; 619 } 620 part = part.substring(0, part.length() - 1); 621 return new BigInteger (part); 623 } 627 628 639 private static BigDecimal parseBigDecimal( 640 String whole, 641 String part, 642 int index) 643 throws IllegalArgumentException { 644 if (part == null) { 645 return null; 646 } 647 part = part.substring(0, part.length() - 1); 648 return new BigDecimal (part); 651 } 655 656 659 private static final XMLGregorianCalendar [] TEST_POINTS = new XMLGregorianCalendar [] { 660 XMLGregorianCalendarImpl.parse("1696-09-01T00:00:00Z"), 661 XMLGregorianCalendarImpl.parse("1697-02-01T00:00:00Z"), 662 XMLGregorianCalendarImpl.parse("1903-03-01T00:00:00Z"), 663 XMLGregorianCalendarImpl.parse("1903-07-01T00:00:00Z") 664 }; 665 666 696 public int compare(Duration rhs) { 697 698 BigInteger maxintAsBigInteger = BigInteger.valueOf((long) Integer.MAX_VALUE); 699 BigInteger minintAsBigInteger = BigInteger.valueOf((long) Integer.MIN_VALUE); 700 701 if (years != null && years.compareTo(maxintAsBigInteger) == 1) { 703 throw new UnsupportedOperationException ( 704 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 705 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), years.toString()}) 706 ); 710 } 711 if (months != null && months.compareTo(maxintAsBigInteger) == 1) { 712 throw new UnsupportedOperationException ( 713 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 714 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), months.toString()}) 715 716 ); 720 } 721 if (days != null && days.compareTo(maxintAsBigInteger) == 1) { 722 throw new UnsupportedOperationException ( 723 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 724 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), days.toString()}) 725 726 ); 730 } 731 if (hours != null && hours.compareTo(maxintAsBigInteger) == 1) { 732 throw new UnsupportedOperationException ( 733 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 734 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), hours.toString()}) 735 736 ); 740 } 741 if (minutes != null && minutes.compareTo(maxintAsBigInteger) == 1) { 742 throw new UnsupportedOperationException ( 743 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 744 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), minutes.toString()}) 745 746 ); 750 } 751 if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) { 752 throw new UnsupportedOperationException ( 753 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 754 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), seconds.toString()}) 755 756 ); 760 } 761 762 BigInteger rhsYears = (BigInteger ) rhs.getField(DatatypeConstants.YEARS); 764 if (rhsYears != null && rhsYears.compareTo(maxintAsBigInteger) == 1) { 765 throw new UnsupportedOperationException ( 766 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 767 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.YEARS.toString(), rhsYears.toString()}) 768 769 ); 773 } 774 BigInteger rhsMonths = (BigInteger ) rhs.getField(DatatypeConstants.MONTHS); 775 if (rhsMonths != null && rhsMonths.compareTo(maxintAsBigInteger) == 1) { 776 throw new UnsupportedOperationException ( 777 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 778 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MONTHS.toString(), rhsMonths.toString()}) 779 780 ); 784 } 785 BigInteger rhsDays = (BigInteger ) rhs.getField(DatatypeConstants.DAYS); 786 if (rhsDays != null && rhsDays.compareTo(maxintAsBigInteger) == 1) { 787 throw new UnsupportedOperationException ( 788 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 789 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.DAYS.toString(), rhsDays.toString()}) 790 791 ); 795 } 796 BigInteger rhsHours = (BigInteger ) rhs.getField(DatatypeConstants.HOURS); 797 if (rhsHours != null && rhsHours.compareTo(maxintAsBigInteger) == 1) { 798 throw new UnsupportedOperationException ( 799 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 800 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.HOURS.toString(), rhsHours.toString()}) 801 802 ); 806 } 807 BigInteger rhsMinutes = (BigInteger ) rhs.getField(DatatypeConstants.MINUTES); 808 if (rhsMinutes != null && rhsMinutes.compareTo(maxintAsBigInteger) == 1) { 809 throw new UnsupportedOperationException ( 810 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 811 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.MINUTES.toString(), rhsMinutes.toString()}) 812 813 ); 817 } 818 BigDecimal rhsSecondsAsBigDecimal = (BigDecimal ) rhs.getField(DatatypeConstants.SECONDS); 819 BigInteger rhsSeconds = null; 820 if ( rhsSecondsAsBigDecimal != null ) { 821 rhsSeconds = rhsSecondsAsBigDecimal.toBigInteger(); 822 } 823 if (rhsSeconds != null && rhsSeconds.compareTo(maxintAsBigInteger) == 1) { 824 throw new UnsupportedOperationException ( 825 DatatypeMessageFormatter.formatMessage(null, "TooLarge", 826 new Object []{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), rhsSeconds.toString()}) 827 828 ); 832 } 833 834 GregorianCalendar lhsCalendar = new GregorianCalendar ( 836 1970, 837 1, 838 1, 839 0, 840 0, 841 0); 842 lhsCalendar.add(GregorianCalendar.YEAR, getYears() * getSign()); 843 lhsCalendar.add(GregorianCalendar.MONTH, getMonths() * getSign()); 844 lhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, getDays() * getSign()); 845 lhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, getHours() * getSign()); 846 lhsCalendar.add(GregorianCalendar.MINUTE, getMinutes() * getSign()); 847 lhsCalendar.add(GregorianCalendar.SECOND, getSeconds() * getSign()); 848 849 GregorianCalendar rhsCalendar = new GregorianCalendar ( 851 1970, 852 1, 853 1, 854 0, 855 0, 856 0); 857 rhsCalendar.add(GregorianCalendar.YEAR, rhs.getYears() * rhs.getSign()); 858 rhsCalendar.add(GregorianCalendar.MONTH, rhs.getMonths() * rhs.getSign()); 859 rhsCalendar.add(GregorianCalendar.DAY_OF_YEAR, rhs.getDays() * rhs.getSign()); 860 rhsCalendar.add(GregorianCalendar.HOUR_OF_DAY, rhs.getHours() * rhs.getSign()); 861 rhsCalendar.add(GregorianCalendar.MINUTE, rhs.getMinutes() * rhs.getSign()); 862 rhsCalendar.add(GregorianCalendar.SECOND, rhs.getSeconds() * rhs.getSign()); 863 864 if (lhsCalendar.before(rhsCalendar)) { 865 return DatatypeConstants.LESSER; 866 } 867 868 if (lhsCalendar.after(rhsCalendar)) { 869 return DatatypeConstants.GREATER; 870 } 871 872 if (lhsCalendar.equals(rhsCalendar)) { 873 return DatatypeConstants.EQUAL; 874 } 875 876 return DatatypeConstants.INDETERMINATE; 877 } 878 879 884 public int hashCode() { 885 Calendar cal = TEST_POINTS[0].toGregorianCalendar(); 887 this.addTo(cal); 888 return (int) getCalendarTimeInMillis(cal); 889 } 890 891 910 public String toString() { 911 StringBuffer buf = new StringBuffer (); 912 if (signum < 0) { 913 buf.append('-'); 914 } 915 buf.append('P'); 916 917 if (years != null) { 918 buf.append(years + "Y"); 919 } 920 if (months != null) { 921 buf.append(months + "M"); 922 } 923 if (days != null) { 924 buf.append(days + "D"); 925 } 926 927 if (hours != null || minutes != null || seconds != null) { 928 buf.append('T'); 929 if (hours != null) { 930 buf.append(hours + "H"); 931 } 932 if (minutes != null) { 933 buf.append(minutes + "M"); 934 } 935 if (seconds != null) { 936 buf.append(toString(seconds) + "S"); 937 } 938 } 939 940 return buf.toString(); 941 } 942 943 953 private String toString(BigDecimal bd) { 954 String intString = bd.unscaledValue().toString(); 955 int scale = bd.scale(); 956 957 if (scale == 0) { 958 return intString; 959 } 960 961 962 StringBuffer buf; 963 int insertionPoint = intString.length() - scale; 964 if (insertionPoint == 0) { 965 return "0." + intString; 966 } else if (insertionPoint > 0) { 967 buf = new StringBuffer (intString); 968 buf.insert(insertionPoint, '.'); 969 } else { 970 buf = new StringBuffer (3 - insertionPoint + intString.length()); 971 buf.append("0."); 972 for (int i = 0; i < -insertionPoint; i++) { 973 buf.append('0'); 974 } 975 buf.append(intString); 976 } 977 return buf.toString(); 978 } 979 980 995 public boolean isSet(DatatypeConstants.Field field) { 996 997 if (field == null) { 998 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)" ; 999 throw new NullPointerException ( 1000 DatatypeMessageFormatter.formatMessage(null, "FieldCannotBeNull", new Object []{methodName}) 1002 ); 1003 } 1004 1005 if (field == DatatypeConstants.YEARS) { 1006 return years != null; 1007 } 1008 1009 if (field == DatatypeConstants.MONTHS) { 1010 return months != null; 1011 } 1012 1013 if (field == DatatypeConstants.DAYS) { 1014 return days != null; 1015 } 1016 1017 if (field == DatatypeConstants.HOURS) { 1018 return hours != null; 1019 } 1020 1021 if (field == DatatypeConstants.MINUTES) { 1022 return minutes != null; 1023 } 1024 1025 if (field == DatatypeConstants.SECONDS) { 1026 return seconds != null; 1027 } 1028 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field)"; 1029 1030 throw new IllegalArgumentException ( 1031 DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object []{methodName, field.toString()}) 1032 ); 1033 1034 } 1035 1036 1060 public Number getField(DatatypeConstants.Field field) { 1061 1062 if (field == null) { 1063 String methodName = "javax.xml.datatype.Duration" + "#isSet(DatatypeConstants.Field field) " ; 1064 1065 throw new NullPointerException ( 1066 DatatypeMessageFormatter.formatMessage(null,"FieldCannotBeNull", new Object []{methodName}) 1067 ); 1068 } 1069 1070 if (field == DatatypeConstants.YEARS) { 1071 return years; 1072 } 1073 1074 if (field == DatatypeConstants.MONTHS) { 1075 return months; 1076 } 1077 1078 if (field == DatatypeConstants.DAYS) { 1079 return days; 1080 } 1081 1082 if (field == DatatypeConstants.HOURS) { 1083 return hours; 1084 } 1085 1086 if (field == DatatypeConstants.MINUTES) { 1087 return minutes; 1088 } 1089 1090 if (field == DatatypeConstants.SECONDS) { 1091 return seconds; 1092 } 1093 1100 String methodName = "javax.xml.datatype.Duration" + "#(getSet(DatatypeConstants.Field field)"; 1101 1102 throw new IllegalArgumentException ( 1103 DatatypeMessageFormatter.formatMessage(null,"UnknownField", new Object []{methodName, field.toString()}) 1104 ); 1105 1106 } 1107 1108 1127 public int getYears() { 1128 return getInt(DatatypeConstants.YEARS); 1129 } 1130 1131 1140 public int getMonths() { 1141 return getInt(DatatypeConstants.MONTHS); 1142 } 1143 1144 1153 public int getDays() { 1154 return getInt(DatatypeConstants.DAYS); 1155 } 1156 1157 1167 public int getHours() { 1168 return getInt(DatatypeConstants.HOURS); 1169 } 1170 1171 1181 public int getMinutes() { 1182 return getInt(DatatypeConstants.MINUTES); 1183 } 1184 1185 1196 public int getSeconds() { 1197 return getInt(DatatypeConstants.SECONDS); 1198 } 1199 1200 1209 private int getInt(DatatypeConstants.Field field) { 1210 Number n = getField(field); 1211 if (n == null) { 1212 return 0; 1213 } else { 1214 return n.intValue(); 1215 } 1216 } 1217 1218 1248 public long getTimeInMillis(final Calendar startInstant) { 1249 Calendar cal = (Calendar ) startInstant.clone(); 1250 addTo(cal); 1251 return getCalendarTimeInMillis(cal) 1252 - getCalendarTimeInMillis(startInstant); 1253 } 1254 1255 1286 public long getTimeInMillis(final Date startInstant) { 1287 Calendar cal = new GregorianCalendar (); 1288 cal.setTime(startInstant); 1289 this.addTo(cal); 1290 return getCalendarTimeInMillis(cal) - startInstant.getTime(); 1291 } 1292 1293 1317 1347 public Duration normalizeWith(Calendar startTimeInstant) { 1348 1349 Calendar c = (Calendar ) startTimeInstant.clone(); 1350 1351 c.add(Calendar.YEAR, getYears() * signum); 1354 c.add(Calendar.MONTH, getMonths() * signum); 1355 c.add(Calendar.DAY_OF_MONTH, getDays() * signum); 1356 1357 long diff = getCalendarTimeInMillis(c) - getCalendarTimeInMillis(startTimeInstant); 1359 int days = (int) (diff / (1000L * 60L * 60L * 24L)); 1360 1361 return new DurationImpl( 1362 days >= 0, 1363 null, 1364 null, 1365 wrap(Math.abs(days)), 1366 (BigInteger ) getField(DatatypeConstants.HOURS), 1367 (BigInteger ) getField(DatatypeConstants.MINUTES), 1368 (BigDecimal ) getField(DatatypeConstants.SECONDS)); 1369 } 1370 1371 1387 public Duration multiply(int factor) { 1388 return multiply(BigDecimal.valueOf(factor)); 1389 } 1390 1391 1438 public Duration multiply(BigDecimal factor) { 1439 BigDecimal carry = ZERO; 1440 int factorSign = factor.signum(); 1441 factor = factor.abs(); 1442 1443 BigDecimal [] buf = new BigDecimal [6]; 1444 1445 for (int i = 0; i < 5; i++) { 1446 BigDecimal bd = getFieldAsBigDecimal(FIELDS[i]); 1447 bd = bd.multiply(factor).add(carry); 1448 1449 buf[i] = bd.setScale(0, BigDecimal.ROUND_DOWN); 1450 1451 bd = bd.subtract(buf[i]); 1452 if (i == 1) { 1453 if (bd.signum() != 0) { 1454 throw new IllegalStateException (); } else { 1456 carry = ZERO; 1457 } 1458 } else { 1459 carry = bd.multiply(FACTORS[i]); 1460 } 1461 } 1462 1463 if (seconds != null) { 1464 buf[5] = seconds.multiply(factor).add(carry); 1465 } else { 1466 buf[5] = carry; 1467 } 1468 1469 return new DurationImpl( 1470 this.signum * factorSign >= 0, 1471 toBigInteger(buf[0], null == years), 1472 toBigInteger(buf[1], null == months), 1473 toBigInteger(buf[2], null == days), 1474 toBigInteger(buf[3], null == hours), 1475 toBigInteger(buf[4], null == minutes), 1476 (buf[5].signum() == 0 && seconds == null) ? null : buf[5]); 1477 } 1478 1479 1488 private BigDecimal getFieldAsBigDecimal(DatatypeConstants.Field f) { 1489 if (f == DatatypeConstants.SECONDS) { 1490 if (seconds != null) { 1491 return seconds; 1492 } else { 1493 return ZERO; 1494 } 1495 } else { 1496 BigInteger bi = (BigInteger ) getField(f); 1497 if (bi == null) { 1498 return ZERO; 1499 } else { 1500 return new BigDecimal (bi); 1501 } 1502 } 1503 } 1504 1505 1513 private static BigInteger toBigInteger( 1514 BigDecimal value, 1515 boolean canBeNull) { 1516 if (canBeNull && value.signum() == 0) { 1517 return null; 1518 } else { 1519 return value.unscaledValue(); 1520 } 1521 } 1522 1523 1527 private static final BigDecimal [] FACTORS = new BigDecimal []{ 1528 BigDecimal.valueOf(12), 1529 null, 1530 BigDecimal.valueOf(24), 1531 BigDecimal.valueOf(60), 1532 BigDecimal.valueOf(60) 1533 }; 1534 1535 1585 public Duration add(final Duration rhs) { 1586 Duration lhs = this; 1587 BigDecimal [] buf = new BigDecimal [6]; 1588 1589 buf[0] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.YEARS), 1590 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.YEARS), rhs.getSign())); 1591 buf[1] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.MONTHS), 1592 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.MONTHS), rhs.getSign())); 1593 buf[2] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.DAYS), 1594 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.DAYS), rhs.getSign())); 1595 buf[3] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.HOURS), 1596 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.HOURS), rhs.getSign())); 1597 buf[4] = sanitize((BigInteger ) lhs.getField(DatatypeConstants.MINUTES), 1598 lhs.getSign()).add(sanitize((BigInteger ) rhs.getField(DatatypeConstants.MINUTES), rhs.getSign())); 1599 buf[5] = sanitize((BigDecimal ) lhs.getField(DatatypeConstants.SECONDS), 1600 lhs.getSign()).add(sanitize((BigDecimal ) rhs.getField(DatatypeConstants.SECONDS), rhs.getSign())); 1601 1602 alignSigns(buf, 0, 2); alignSigns(buf, 2, 6); 1606 int s = 0; 1608 for (int i = 0; i < 6; i++) { 1609 if (s * buf[i].signum() < 0) { 1610 throw new IllegalStateException (); 1611 } 1612 if (s == 0) { 1613 s = buf[i].signum(); 1614 } 1615 } 1616 1617 return new DurationImpl( 1618 s >= 0, 1619 toBigInteger(sanitize(buf[0], s), 1620 lhs.getField(DatatypeConstants.YEARS) == null && rhs.getField(DatatypeConstants.YEARS) == null), 1621 toBigInteger(sanitize(buf[1], s), 1622 lhs.getField(DatatypeConstants.MONTHS) == null && rhs.getField(DatatypeConstants.MONTHS) == null), 1623 toBigInteger(sanitize(buf[2], s), 1624 lhs.getField(DatatypeConstants.DAYS) == null && rhs.getField(DatatypeConstants.DAYS) == null), 1625 toBigInteger(sanitize(buf[3], s), 1626 lhs.getField(DatatypeConstants.HOURS) == null && rhs.getField(DatatypeConstants.HOURS) == null), 1627 toBigInteger(sanitize(buf[4], s), 1628 lhs.getField(DatatypeConstants.MINUTES) == null && rhs.getField(DatatypeConstants.MINUTES) == null), 1629 (buf[5].signum() == 0 1630 && lhs.getField(DatatypeConstants.SECONDS) == null 1631 && rhs.getField(DatatypeConstants.SECONDS) == null) ? null : sanitize(buf[5], s)); 1632 } 1633 1634 private static void alignSigns(BigDecimal [] buf, int start, int end) { 1635 boolean touched; 1637 1638 do { touched = false; 1640 int s = 0; 1642 for (int i = start; i < end; i++) { 1643 if (s * buf[i].signum() < 0) { 1644 touched = true; 1646 1647 BigDecimal borrow = 1649 buf[i].abs().divide( 1650 FACTORS[i - 1], 1651 BigDecimal.ROUND_UP); 1652 if (buf[i].signum() > 0) { 1653 borrow = borrow.negate(); 1654 } 1655 1656 buf[i - 1] = buf[i - 1].subtract(borrow); 1658 buf[i] = buf[i].add(borrow.multiply(FACTORS[i - 1])); 1659 } 1660 if (buf[i].signum() != 0) { 1661 s = buf[i].signum(); 1662 } 1663 } 1664 } while (touched); 1665 } 1666 1667 1675 private static BigDecimal sanitize(BigInteger value, int signum) { 1676 if (signum == 0 || value == null) { 1677 return ZERO; 1678 } 1679 if (signum > 0) { 1680 return new BigDecimal (value); 1681 } 1682 return new BigDecimal (value.negate()); 1683 } 1684 1685 1693 static BigDecimal sanitize(BigDecimal value, int signum) { 1694 if (signum == 0 || value == null) { 1695 return ZERO; 1696 } 1697 if (signum > 0) { 1698 return value; 1699 } 1700 return value.negate(); 1701 } 1702 1703 1752 public Duration subtract(final Duration rhs) { 1753 return add(rhs.negate()); 1754 } 1755 1756 1768 public Duration negate() { 1769 return new DurationImpl( 1770 signum <= 0, 1771 years, 1772 months, 1773 days, 1774 hours, 1775 minutes, 1776 seconds); 1777 } 1778 1779 1786 public int signum() { 1787 return signum; 1788 } 1789 1790 1791 1830 public void addTo(Calendar calendar) { 1831 calendar.add(Calendar.YEAR, getYears() * signum); 1832 calendar.add(Calendar.MONTH, getMonths() * signum); 1833 calendar.add(Calendar.DAY_OF_MONTH, getDays() * signum); 1834 calendar.add(Calendar.HOUR, getHours() * signum); 1835 calendar.add(Calendar.MINUTE, getMinutes() * signum); 1836 calendar.add(Calendar.SECOND, getSeconds() * signum); 1837 1838 if (seconds != null) { 1839 BigDecimal fraction = 1840 seconds.subtract(seconds.setScale(0, BigDecimal.ROUND_DOWN)); 1841 int millisec = fraction.movePointRight(3).intValue(); 1842 calendar.add(Calendar.MILLISECOND, millisec * signum); 1843 } 1844 } 1845 1846 1867 public void addTo(Date date) { 1868 Calendar cal = new GregorianCalendar (); 1869 cal.setTime(date); this.addTo(cal); 1871 date.setTime(getCalendarTimeInMillis(cal)); 1872 } 1873 1874 1880 private static final long serialVersionUID = 1L; 1881 1882 1890 private Object writeReplace() throws IOException { 1891 return new DurationStream(this.toString()); 1892 } 1893 1894 1899 private static class DurationStream implements Serializable { 1900 private final String lexical; 1901 1902 private DurationStream(String _lexical) { 1903 this.lexical = _lexical; 1904 } 1905 1906 private Object readResolve() throws ObjectStreamException { 1907 return new DurationImpl(lexical); 1909 } 1913 1914 private static final long serialVersionUID = 1L; 1915 } 1916 1917 1925 private static long getCalendarTimeInMillis(Calendar cal) { 1926 return cal.getTime().getTime(); 1927 } 1928} 1929 1930 | Popular Tags |