1 16 17 package org.apache.xerces.impl.dv.xs; 18 19 import javax.xml.datatype.DatatypeFactory ; 20 import javax.xml.datatype.Duration ; 21 import javax.xml.datatype.XMLGregorianCalendar ; 22 23 import org.apache.xerces.impl.Constants; 24 import org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl; 25 import org.apache.xerces.xs.datatypes.XSDateTime; 26 27 46 public abstract class AbstractDateTimeDV extends TypeValidator { 47 48 private static final boolean DEBUG=false; 50 51 53 54 protected final static int YEAR=2000; 57 protected final static int MONTH=01; 58 protected final static int DAY = 01; 59 60 protected DatatypeFactory factory = new DatatypeFactoryImpl(); 61 62 public short getAllowedFacets(){ 63 return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE ); 64 } 66 67 public boolean isIdentical (Object value1, Object value2) { 71 if (!(value1 instanceof DateTimeData) || !(value2 instanceof DateTimeData)) { 72 return false; 73 } 74 75 DateTimeData v1 = (DateTimeData)value1; 76 DateTimeData v2 = (DateTimeData)value2; 77 78 if ((v1.timezoneHr == v2.timezoneHr) && (v1.timezoneMin == v2.timezoneMin)) { 81 return v1.equals(v2); 82 } 83 84 return false; 85 } 87 public int compare (Object value1, Object value2) { 89 return compareDates(((DateTimeData)value1), 90 ((DateTimeData)value2), true); 91 } 93 102 protected short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) { 103 if (date1.utc == date2.utc) { 104 return compareOrder(date1, date2); 105 } 106 short c1, c2; 107 108 DateTimeData tempDate = new DateTimeData(null, this); 109 110 if ( date1.utc=='Z' ) { 111 112 cloneDate(date2, tempDate); tempDate.timezoneHr=14; 116 tempDate.timezoneMin = 0; 117 tempDate.utc='+'; 118 normalize(tempDate); 119 c1 = compareOrder(date1, tempDate); 120 if (c1 == LESS_THAN) 121 return c1; 122 123 cloneDate(date2, tempDate); tempDate.timezoneHr = -14; 127 tempDate.timezoneMin = 0; 128 tempDate.utc='-'; 129 normalize(tempDate); 130 c2 = compareOrder(date1, tempDate); 131 if (c2 == GREATER_THAN) 132 return c2; 133 134 return INDETERMINATE; 135 } 136 else if ( date2.utc=='Z' ) { 137 138 cloneDate(date1, tempDate); tempDate.timezoneHr = -14; 142 tempDate.timezoneMin = 0; 143 tempDate.utc='-'; 144 if (DEBUG) { 145 System.out.println("tempDate=" + dateToString(tempDate)); 146 } 147 normalize(tempDate); 148 c1 = compareOrder(tempDate, date2); 149 if (DEBUG) { 150 System.out.println("date=" + dateToString(date2)); 151 System.out.println("tempDate=" + dateToString(tempDate)); 152 } 153 if (c1 == LESS_THAN) 154 return c1; 155 156 cloneDate(date1, tempDate); tempDate.timezoneHr = 14; 160 tempDate.timezoneMin = 0; 161 tempDate.utc='+'; 162 normalize(tempDate); 163 c2 = compareOrder(tempDate, date2); 164 if (DEBUG) { 165 System.out.println("tempDate=" + dateToString(tempDate)); 166 } 167 if (c2 == GREATER_THAN) 168 return c2; 169 170 return INDETERMINATE; 171 } 172 return INDETERMINATE; 173 174 } 175 176 184 protected short compareOrder(DateTimeData date1, DateTimeData date2) { 185 if(date1.position < 1) { 186 if (date1.year < date2.year) 187 return -1; 188 if (date1.year > date2.year) 189 return 1; 190 } 191 if(date1.position < 2) { 192 if (date1.month < date2.month) 193 return -1; 194 if (date1.month > date2.month) 195 return 1; 196 } 197 if (date1.day < date2.day) 198 return -1; 199 if (date1.day > date2.day) 200 return 1; 201 if (date1.hour < date2.hour) 202 return -1; 203 if (date1.hour > date2.hour) 204 return 1; 205 if (date1.minute < date2.minute) 206 return -1; 207 if (date1.minute > date2.minute) 208 return 1; 209 if (date1.second < date2.second) 210 return -1; 211 if (date1.second > date2.second) 212 return 1; 213 if (date1.utc < date2.utc) 214 return -1; 215 if (date1.utc > date2.utc) 216 return 1; 217 return 0; 218 } 219 220 228 protected void getTime (String buffer, int start, int end, DateTimeData data) throws RuntimeException { 229 230 int stop = start+2; 231 232 data.hour=parseInt(buffer, start,stop); 234 235 237 if (buffer.charAt(stop++)!=':') { 238 throw new RuntimeException ("Error in parsing time zone" ); 239 } 240 start = stop; 241 stop = stop+2; 242 data.minute=parseInt(buffer, start,stop); 243 244 if (buffer.charAt(stop++)!=':') { 246 throw new RuntimeException ("Error in parsing time zone" ); 247 } 248 249 int sign = findUTCSign(buffer, start, end); 251 252 start = stop; 254 stop = sign < 0 ? end : sign; 255 data.second = parseSecond(buffer, start, stop); 256 257 if (sign > 0) { 259 getTimeZone(buffer, data, sign, end); 260 } 261 } 262 263 272 protected int getDate (String buffer, int start, int end, DateTimeData date) throws RuntimeException { 273 274 start = getYearMonth(buffer, start, end, date); 275 276 if (buffer.charAt(start++) !='-') { 277 throw new RuntimeException ("CCYY-MM must be followed by '-' sign"); 278 } 279 int stop = start + 2; 280 date.day=parseInt(buffer, start, stop); 281 return stop; 282 } 283 284 293 protected int getYearMonth (String buffer, int start, int end, DateTimeData date) throws RuntimeException { 294 295 if ( buffer.charAt(0)=='-' ) { 296 start++; 300 } 301 int i = indexOf(buffer, start, end, '-'); 302 if ( i==-1 ) throw new RuntimeException ("Year separator is missing or misplaced"); 303 int length = i-start; 304 if (length<4) { 305 throw new RuntimeException ("Year must have 'CCYY' format"); 306 } 307 else if (length > 4 && buffer.charAt(start)=='0'){ 308 throw new RuntimeException ("Leading zeros are required if the year value would otherwise have fewer than four digits; otherwise they are forbidden"); 309 } 310 date.year= parseIntYear(buffer, i); 311 if (buffer.charAt(i)!='-') { 312 throw new RuntimeException ("CCYY must be followed by '-' sign"); 313 } 314 start = ++i; 315 i = start +2; 316 date.month=parseInt(buffer, start, i); 317 return i; } 319 320 328 protected void parseTimeZone (String buffer, int start, int end, DateTimeData date) throws RuntimeException { 329 330 332 if ( start < end ) { 333 if (!isNextCharUTCSign(buffer, start, end)) { 334 throw new RuntimeException ("Error in month parsing"); 335 } 336 else { 337 getTimeZone(buffer, date, start, end); 338 } 339 } 340 } 341 342 349 protected void getTimeZone (String buffer, DateTimeData data, int sign, int end) throws RuntimeException { 350 data.utc=buffer.charAt(sign); 351 352 if ( buffer.charAt(sign) == 'Z' ) { 353 if (end>(++sign)) { 354 throw new RuntimeException ("Error in parsing time zone"); 355 } 356 return; 357 } 358 if ( sign<=(end-6) ) { 359 360 int negate = buffer.charAt(sign) == '-'?-1:1; 361 int stop = ++sign+2; 363 data.timezoneHr = negate*parseInt(buffer, sign, stop); 364 if (buffer.charAt(stop++)!=':') { 365 throw new RuntimeException ("Error in parsing time zone" ); 366 } 367 368 data.timezoneMin = negate*parseInt(buffer, stop, stop+2); 370 371 if ( stop+2!=end ) { 372 throw new RuntimeException ("Error in parsing time zone"); 373 } 374 if(data.timezoneHr != 0 || data.timezoneMin != 0) 375 data.normalized = false; 376 } 377 else { 378 throw new RuntimeException ("Error in parsing time zone"); 379 } 380 if ( DEBUG ) { 381 System.out.println("time[hh]="+data.timezoneHr + " time[mm]=" +data.timezoneMin); 382 } 383 } 384 385 393 protected int indexOf (String buffer, int start, int end, char ch) { 394 for ( int i=start;i<end;i++ ) { 395 if ( buffer.charAt(i) == ch ) { 396 return i; 397 } 398 } 399 return -1; 400 } 401 402 408 protected void validateDateTime (DateTimeData data) { 409 410 413 416 if (!Constants.SCHEMA_1_1_SUPPORT && data.year==0 ) { 417 throw new RuntimeException ("The year \"0000\" is an illegal year value"); 418 419 } 420 421 if ( data.month<1 || data.month>12 ) { 422 throw new RuntimeException ("The month must have values 1 to 12"); 423 424 } 425 426 if ( data.day>maxDayInMonthFor(data.year, data.month) || data.day<1 ) { 428 throw new RuntimeException ("The day must have values 1 to 31"); 429 } 430 431 if ( data.hour>23 || data.hour<0 ) { 433 if (data.hour == 24 && data.minute == 0 && data.second == 0) { 434 data.hour = 0; 435 if (++data.day > maxDayInMonthFor(data.year, data.month)) { 436 data.day = 1; 437 if (++data.month > 12) { 438 data.month = 1; 439 if (Constants.SCHEMA_1_1_SUPPORT) { 440 ++data.year; 441 } 442 else if (++data.year == 0) { 443 data.year = 1; 444 } 445 } 446 } 447 } 448 else { 449 throw new RuntimeException ("Hour must have values 0-23, unless 24:00:00"); 450 } 451 } 452 453 if ( data.minute>59 || data.minute<0 ) { 455 throw new RuntimeException ("Minute must have values 0-59"); 456 } 457 458 if ( data.second>=60 || data.second<0 ) { 460 throw new RuntimeException ("Second must have values 0-59"); 461 462 } 463 464 if ( data.timezoneHr>14 || data.timezoneHr<-14 ) { 466 throw new RuntimeException ("Time zone should have range -14:00 to +14:00"); 467 } 468 else { 469 if((data.timezoneHr == 14 || data.timezoneHr == -14) && data.timezoneMin != 0) 470 throw new RuntimeException ("Time zone should have range -14:00 to +14:00"); 471 else if(data.timezoneMin > 59 || data.timezoneMin < -59) 472 throw new RuntimeException ("Minute must have values 0-59"); 473 } 474 475 } 476 477 484 protected int findUTCSign (String buffer, int start, int end) { 485 int c; 486 for ( int i=start;i<end;i++ ) { 487 c=buffer.charAt(i); 488 if ( c == 'Z' || c=='+' || c=='-' ) { 489 return i; 490 } 491 492 } 493 return -1; 494 } 495 496 499 protected final boolean isNextCharUTCSign(String buffer, int start, int end) { 500 if (start < end) { 501 char c = buffer.charAt(start); 502 return (c == 'Z' || c == '+' || c == '-'); 503 } 504 return false; 505 } 506 507 515 protected int parseInt (String buffer, int start, int end) 516 throws NumberFormatException { 517 int radix=10; 519 int result = 0; 520 int digit=0; 521 int limit = -Integer.MAX_VALUE; 522 int multmin = limit / radix; 523 int i = start; 524 do { 525 digit = getDigit(buffer.charAt(i)); 526 if ( digit < 0 ) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 527 if ( result < multmin ) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 528 result *= radix; 529 if ( result < limit + digit ) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 530 result -= digit; 531 532 }while ( ++i < end ); 533 return -result; 534 } 535 536 protected int parseIntYear (String buffer, int end){ 538 int radix=10; 539 int result = 0; 540 boolean negative = false; 541 int i=0; 542 int limit; 543 int multmin; 544 int digit=0; 545 546 if (buffer.charAt(0) == '-'){ 547 negative = true; 548 limit = Integer.MIN_VALUE; 549 i++; 550 551 } 552 else{ 553 limit = -Integer.MAX_VALUE; 554 } 555 multmin = limit / radix; 556 while (i < end) 557 { 558 digit = getDigit(buffer.charAt(i++)); 559 if (digit < 0) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 560 if (result < multmin) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 561 result *= radix; 562 if (result < limit + digit) throw new NumberFormatException ("'" + buffer + "' has wrong format"); 563 result -= digit; 564 } 565 566 if (negative) 567 { 568 if (i > 1) return result; 569 else throw new NumberFormatException ("'" + buffer + "' has wrong format"); 570 } 571 return -result; 572 573 } 574 575 581 protected void normalize(DateTimeData date) { 582 583 587 int negate = -1; 589 590 if ( DEBUG ) { 591 System.out.println("==>date.minute"+date.minute); 592 System.out.println("==>date.timezoneMin" +date.timezoneMin); 593 } 594 int temp = date.minute + negate * date.timezoneMin; 595 int carry = fQuotient (temp, 60); 596 date.minute= mod(temp, 60, carry); 597 598 if ( DEBUG ) { 599 System.out.println("==>carry: " + carry); 600 } 601 temp = date.hour + negate * date.timezoneHr + carry; 603 carry = fQuotient(temp, 24); 604 date.hour=mod(temp, 24, carry); 605 if ( DEBUG ) { 606 System.out.println("==>date.hour"+date.hour); 607 System.out.println("==>carry: " + carry); 608 } 609 610 date.day=date.day+carry; 611 612 while ( true ) { 613 temp=maxDayInMonthFor(date.year, date.month); 614 if (date.day<1) { 615 date.day = date.day + maxDayInMonthFor(date.year, date.month-1); 616 carry=-1; 617 } 618 else if ( date.day>temp ) { 619 date.day=date.day-temp; 620 carry=1; 621 } 622 else { 623 break; 624 } 625 temp=date.month+carry; 626 date.month=modulo(temp, 1, 13); 627 date.year=date.year+fQuotient(temp, 1, 13); 628 if(date.year == 0 && !Constants.SCHEMA_1_1_SUPPORT) { 629 date.year = (date.timezoneHr < 0 || date.timezoneMin < 0)?1:-1; 630 } 631 } 632 date.utc='Z'; 633 } 634 635 636 639 protected void saveUnnormalized(DateTimeData date) { 640 date.unNormYear = date.year; 641 date.unNormMonth = date.month; 642 date.unNormDay = date.day; 643 date.unNormHour = date.hour; 644 date.unNormMinute = date.minute; 645 date.unNormSecond = date.second; 646 } 647 648 653 protected void resetDateObj(DateTimeData data) { 654 data.year = 0; 655 data.month = 0; 656 data.day = 0; 657 data.hour = 0; 658 data.minute = 0; 659 data.second = 0; 660 data.utc = 0; 661 data.timezoneHr = 0; 662 data.timezoneMin = 0; 663 } 664 665 673 protected int maxDayInMonthFor(int year, int month) { 674 if ( month==4 || month==6 || month==9 || month==11 ) { 676 return 30; 677 } 678 else if ( month==2 ) { 679 if ( isLeapYear(year) ) { 680 return 29; 681 } 682 else { 683 return 28; 684 } 685 } 686 else { 687 return 31; 688 } 689 } 690 691 private boolean isLeapYear(int year) { 692 693 return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); 695 } 696 697 protected int mod (int a, int b, int quotient) { 701 return (a - quotient*b) ; 703 } 704 705 protected int fQuotient (int a, int b) { 709 710 return (int)Math.floor((float)a/b); 712 } 713 714 protected int modulo (int temp, int low, int high) { 718 int a = temp - low; 720 int b = high - low; 721 return (mod (a, b, fQuotient(a, b)) + low) ; 722 } 723 724 protected int fQuotient (int temp, int low, int high) { 728 730 return fQuotient(temp - low, high - low); 731 } 732 733 734 protected String dateToString(DateTimeData date) { 735 StringBuffer message = new StringBuffer (25); 736 append(message, date.year, 4); 737 message.append('-'); 738 append(message, date.month, 2); 739 message.append('-'); 740 append(message, date.day, 2); 741 message.append('T'); 742 append(message, date.hour, 2); 743 message.append(':'); 744 append(message, date.minute, 2); 745 message.append(':'); 746 append(message, date.second); 747 append(message, (char)date.utc, 0); 748 return message.toString(); 749 } 750 751 protected void append(StringBuffer message, int value, int nch) { 752 if (value == Integer.MIN_VALUE) { 753 message.append(value); 754 return; 755 } 756 if (value < 0) { 757 message.append('-'); 758 value = -value; 759 } 760 if (nch == 4) { 761 if (value < 10) 762 message.append("000"); 763 else if (value < 100) 764 message.append("00"); 765 else if (value < 1000) 766 message.append("0"); 767 message.append(value); 768 } 769 else if (nch == 2) { 770 if (value < 10) 771 message.append('0'); 772 message.append(value); 773 } 774 else { 775 if (value != 0) 776 message.append((char)value); 777 } 778 } 779 780 protected void append(StringBuffer message, double value) { 781 if (value < 0) { 782 message.append('-'); 783 value = -value; 784 } 785 if (value < 10) 786 message.append('0'); 787 message.append(value); 788 } 789 790 protected double parseSecond(String buffer, int start, int end) 791 throws NumberFormatException { 792 int dot = -1; 793 for (int i = start; i < end; i++) { 794 char ch = buffer.charAt(i); 795 if (ch == '.') 796 dot = i; 797 else if (ch > '9' || ch < '0') 798 throw new NumberFormatException ("'" + buffer + "' has wrong format"); 799 } 800 if (dot == -1) { 801 if (start+2 != end) 802 throw new NumberFormatException ("'" + buffer + "' has wrong format"); 803 } 804 else if (start+2 != dot || dot+1 == end) { 805 throw new NumberFormatException ("'" + buffer + "' has wrong format"); 806 } 807 return Double.parseDouble(buffer.substring(start, end)); 808 } 809 810 814 private void cloneDate (DateTimeData finalValue, DateTimeData tempDate) { 815 tempDate.year = finalValue.year; 816 tempDate.month = finalValue.month; 817 tempDate.day = finalValue.day; 818 tempDate.hour = finalValue.hour; 819 tempDate.minute = finalValue.minute; 820 tempDate.second = finalValue.second; 821 tempDate.utc = finalValue.utc; 822 tempDate.timezoneHr = finalValue.timezoneHr; 823 tempDate.timezoneMin = finalValue.timezoneMin; 824 } 825 826 829 static final class DateTimeData implements XSDateTime { 830 int year, month, day, hour, minute, utc; 831 double second; 832 int timezoneHr, timezoneMin; 833 private String originalValue; 834 boolean normalized = true; 835 836 int unNormYear; 837 int unNormMonth; 838 int unNormDay; 839 int unNormHour; 840 int unNormMinute; 841 double unNormSecond; 842 843 int position; 846 final AbstractDateTimeDV type; 850 private String canonical; 851 public DateTimeData(String originalValue, AbstractDateTimeDV type) { 852 this.originalValue = originalValue; 853 this.type = type; 854 } 855 public DateTimeData(int year, int month, int day, int hour, int minute, 856 double second, int utc, String originalValue, boolean normalized, AbstractDateTimeDV type) { 857 this.year = year; 858 this.month = month; 859 this.day = day; 860 this.hour = hour; 861 this.minute = minute; 862 this.second = second; 863 this.utc = utc; 864 this.type = type; 865 this.originalValue = originalValue; 866 } 867 public boolean equals(Object obj) { 868 if (!(obj instanceof DateTimeData)) 869 return false; 870 return type.compareDates(this, (DateTimeData)obj, true)==0; 871 } 872 public synchronized String toString() { 873 if (canonical == null) { 874 canonical = type.dateToString(this); 875 } 876 return canonical; 877 } 878 881 public int getYears() { 882 if(type instanceof DurationDV) 883 return 0; 884 return normalized?year:unNormYear; 885 } 886 889 public int getMonths() { 890 if(type instanceof DurationDV) { 891 return year*12 + month; 892 } 893 return normalized?month:unNormMonth; 894 } 895 898 public int getDays() { 899 if(type instanceof DurationDV) 900 return 0; 901 return normalized?day:unNormDay; 902 } 903 906 public int getHours() { 907 if(type instanceof DurationDV) 908 return 0; 909 return normalized?hour:unNormHour; 910 } 911 914 public int getMinutes() { 915 if(type instanceof DurationDV) 916 return 0; 917 return normalized?minute:unNormMinute; 918 } 919 922 public double getSeconds() { 923 if(type instanceof DurationDV) { 924 return day*24*60*60 + hour*60*60 + minute*60 + second; 925 } 926 return normalized?second:unNormSecond; 927 } 928 931 public boolean hasTimeZone() { 932 return utc != 0; 933 } 934 937 public int getTimeZoneHours() { 938 return timezoneHr; 939 } 940 943 public int getTimeZoneMinutes() { 944 return timezoneMin; 945 } 946 949 public String getLexicalValue() { 950 return originalValue; 951 } 952 955 public XSDateTime normalize() { 956 if(!normalized) { 957 DateTimeData dt = (DateTimeData)this.clone(); 958 dt.normalized = true; 959 return dt; 960 } 961 return this; 962 } 963 966 public boolean isNormalized() { 967 return normalized; 968 } 969 970 public Object clone() { 971 DateTimeData dt = new DateTimeData(this.year, this.month, this.day, this.hour, 972 this.minute, this.second, this.utc, this.originalValue, this.normalized, this.type); 973 dt.canonical = this.canonical; 974 dt.position = position; 975 dt.timezoneHr = this.timezoneHr; 976 dt.timezoneMin = this.timezoneMin; 977 dt.unNormYear = this.unNormYear; 978 dt.unNormMonth = this.unNormMonth; 979 dt.unNormDay = this.unNormDay; 980 dt.unNormHour = this.unNormHour; 981 dt.unNormMinute = this.unNormMinute; 982 dt.unNormSecond = this.unNormSecond; 983 return dt; 984 } 985 986 989 public XMLGregorianCalendar getXMLGregorianCalendar() { 990 return type.getXMLGregorianCalendar(this); 991 } 992 995 public Duration getDuration() { 996 return type.getDuration(this); 997 } 998 } 999 1000 protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData data) { 1001 return null; 1002 } 1003 1004 1005 protected Duration getDuration(DateTimeData data) { 1006 return null; 1007 } 1008} 1009 | Popular Tags |