AbstractDateTimeDVpublic abstract class AbstractDateTimeDV extends TypeValidator This is the base class of all date/time datatype validators.
It implements common code for parsing, validating and comparing datatypes.
Classes that extend this class, must implement parse() method.
REVISIT: There are many instance variables, which would cause problems
when we support grammar caching. A grammar is possibly used by
two parser instances at the same time, then the same simple type
decl object can be used to validate two strings at the same time.
-SG |
Fields Summary |
---|
private static final boolean | DEBUG | protected static final int | CY | protected static final int | M | protected static final int | D | protected static final int | h | protected static final int | m | protected static final int | s | protected static final int | ms | protected static final int | utc | protected static final int | hh | protected static final int | mm | protected static final int | TOTAL_SIZE | protected static final int | YEAR | protected static final int | MONTH | protected static final int | DAY |
Methods Summary |
---|
protected void | append(java.lang.StringBuffer message, int value, int nch)
if (value < 0) {
message.append('-");
value = -value;
}
if (nch == 4) {
if (value < 10)
message.append("000");
else if (value < 100)
message.append("00");
else if (value < 1000)
message.append("0");
message.append(value);
}
else if (nch == 2) {
if (value < 10)
message.append('0");
message.append(value);
}
else {
if (value != 0)
message.append((char)value);
}
| private void | cloneDate(int[] finalValue, int[] tempDate)
System.arraycopy(finalValue, 0, tempDate, 0, TOTAL_SIZE);
| public int | compare(java.lang.Object value1, java.lang.Object value2)
return compareDates(((DateTimeData)value1).data,
((DateTimeData)value2).data, true);
| protected short | compareDates(int[] date1, int[] date2, boolean strict)Compare algorithm described in dateDime (3.2.7).
Duration datatype overwrites this method
if ( date1[utc]==date2[utc] ) {
return compareOrder(date1, date2);
}
short c1, c2;
int[] tempDate = new int[TOTAL_SIZE];
int[] timeZone = new int[2];
if ( date1[utc]=='Z" ) {
//compare date1<=date1<=(date2 with time zone -14)
//
cloneDate(date2, tempDate); //clones date1 value to global temporary storage: fTempDate
timeZone[hh]=14;
timeZone[mm]=0;
tempDate[utc]='+";
normalize(tempDate, timeZone);
c1 = compareOrder(date1, tempDate);
if (c1 == LESS_THAN)
return c1;
//compare date1>=(date2 with time zone +14)
//
cloneDate(date2, tempDate); //clones date1 value to global temporary storage: tempDate
timeZone[hh]=14;
timeZone[mm]=0;
tempDate[utc]='-";
normalize(tempDate, timeZone);
c2 = compareOrder(date1, tempDate);
if (c2 == GREATER_THAN)
return c2;
return INDETERMINATE;
}
else if ( date2[utc]=='Z" ) {
//compare (date1 with time zone -14)<=date2
//
cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate
timeZone[hh]=14;
timeZone[mm]=0;
tempDate[utc]='-";
if (DEBUG) {
System.out.println("tempDate=" + dateToString(tempDate));
}
normalize(tempDate, timeZone);
c1 = compareOrder(tempDate, date2);
if (DEBUG) {
System.out.println("date=" + dateToString(date2));
System.out.println("tempDate=" + dateToString(tempDate));
}
if (c1 == LESS_THAN)
return c1;
//compare (date1 with time zone +14)<=date2
//
cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate
timeZone[hh]=14;
timeZone[mm]=0;
tempDate[utc]='+";
normalize(tempDate, timeZone);
c2 = compareOrder(tempDate, date2);
if (DEBUG) {
System.out.println("tempDate=" + dateToString(tempDate));
}
if (c2 == GREATER_THAN)
return c2;
return INDETERMINATE;
}
return INDETERMINATE;
| protected short | compareOrder(int[] date1, int[] date2)Given normalized values, determines order-relation
between give date/time objects.
for ( int i=0;i<TOTAL_SIZE;i++ ) {
if ( date1[i]<date2[i] ) {
return -1;
}
else if ( date1[i]>date2[i] ) {
return 1;
}
}
return 0;
| protected java.lang.String | dateToString(int[] date)
StringBuffer message = new StringBuffer(25);
append(message, date[CY], 4);
message.append('-");
append(message, date[M], 2);
message.append('-");
append(message, date[D], 2);
message.append('T");
append(message, date[h], 2);
message.append(':");
append(message, date[m], 2);
message.append(':");
append(message, date[s], 2);
message.append('.");
message.append(date[ms]);
append(message, (char)date[utc], 0);
return message.toString();
| protected int | fQuotient(int a, int b)
//fQuotient(a, b) = the greatest integer less than or equal to a/b
return (int)Math.floor((float)a/b);
| protected int | fQuotient(int temp, int low, int high)
//fQuotient(a - low, high - low)
return fQuotient(temp - low, high - low);
| protected int | findUTCSign(java.lang.String buffer, int start, int end)Return index of UTC char: 'Z', '+', '-'
int c;
for ( int i=start;i<end;i++ ) {
c=buffer.charAt(i);
if ( c == 'Z" || c=='+" || c=='-" ) {
return i;
}
}
return -1;
| public short | getAllowedFacets()
return ( XSSimpleTypeDecl.FACET_PATTERN | XSSimpleTypeDecl.FACET_WHITESPACE | XSSimpleTypeDecl.FACET_ENUMERATION |XSSimpleTypeDecl.FACET_MAXINCLUSIVE |XSSimpleTypeDecl.FACET_MININCLUSIVE | XSSimpleTypeDecl.FACET_MAXEXCLUSIVE | XSSimpleTypeDecl.FACET_MINEXCLUSIVE );
| protected int | getDate(java.lang.String buffer, int start, int end, int[] date)Parses date CCYY-MM-DD
start = getYearMonth(buffer, start, end, date);
if (buffer.charAt(start++) !='-") {
throw new RuntimeException("CCYY-MM must be followed by '-' sign");
}
int stop = start + 2;
date[D]=parseInt(buffer, start, stop);
return stop;
| protected void | getTime(java.lang.String buffer, int start, int end, int[] data, int[] timeZone)Parses time hh:mm:ss.sss and time zone if any
int stop = start+2;
//get hours (hh)
data[h]=parseInt(buffer, start,stop);
//get minutes (mm)
if (buffer.charAt(stop++)!=':") {
throw new RuntimeException("Error in parsing time zone" );
}
start = stop;
stop = stop+2;
data[m]=parseInt(buffer, start,stop);
//get seconds (ss)
if (buffer.charAt(stop++)!=':") {
throw new RuntimeException("Error in parsing time zone" );
}
start = stop;
stop = stop+2;
data[s]=parseInt(buffer, start,stop);
if (stop == end)
return;
//get miliseconds (ms)
start = stop;
int milisec = buffer.charAt(start) == '." ? start : -1;
//find UTC sign if any
int sign = findUTCSign(buffer, start, end);
//parse miliseconds
if ( milisec != -1 ) {
// The end of millisecond part is between . and
// either the end of the UTC sign
start = sign < 0 ? end : sign;
data[ms]=parseInt(buffer, milisec+1, start);
}
//parse UTC time zone (hh:mm)
if ( sign>0 ) {
if (start != sign)
throw new RuntimeException("Error in parsing time zone" );
getTimeZone(buffer, data, sign, end, timeZone);
}
else if (start != end) {
throw new RuntimeException("Error in parsing time zone" );
}
| protected void | getTimeZone(java.lang.String buffer, int[] data, int sign, int end, int[] timeZone)Parses time zone: 'Z' or {+,-} followed by hh:mm
data[utc]=buffer.charAt(sign);
if ( buffer.charAt(sign) == 'Z" ) {
if (end>(++sign)) {
throw new RuntimeException("Error in parsing time zone");
}
return;
}
if ( sign<=(end-6) ) {
//parse [hh]
int stop = ++sign+2;
timeZone[hh]=parseInt(buffer, sign, stop);
if (buffer.charAt(stop++)!=':") {
throw new RuntimeException("Error in parsing time zone" );
}
//parse [ss]
timeZone[mm]=parseInt(buffer, stop, stop+2);
if ( stop+2!=end ) {
throw new RuntimeException("Error in parsing time zone");
}
}
else {
throw new RuntimeException("Error in parsing time zone");
}
if ( DEBUG ) {
System.out.println("time[hh]="+timeZone[hh] + " time[mm]=" +timeZone[mm]);
}
| protected int | getYearMonth(java.lang.String buffer, int start, int end, int[] date)Parses date CCYY-MM
if ( buffer.charAt(0)=='-" ) {
// REVISIT: date starts with preceding '-' sign
// do we have to do anything with it?
//
start++;
}
int i = indexOf(buffer, start, end, '-");
if ( i==-1 ) throw new RuntimeException("Year separator is missing or misplaced");
int length = i-start;
if (length<4) {
throw new RuntimeException("Year must have 'CCYY' format");
}
else if (length > 4 && buffer.charAt(start)=='0"){
throw new RuntimeException("Leading zeros are required if the year value would otherwise have fewer than four digits; otherwise they are forbidden");
}
date[CY]= parseIntYear(buffer, i);
if (buffer.charAt(i)!='-") {
throw new RuntimeException("CCYY must be followed by '-' sign");
}
start = ++i;
i = start +2;
date[M]=parseInt(buffer, start, i);
return i; //fStart points right after the MONTH
| protected int | indexOf(java.lang.String buffer, int start, int end, char ch)Computes index of given char within StringBuffer
for ( int i=start;i<end;i++ ) {
if ( buffer.charAt(i) == ch ) {
return i;
}
}
return -1;
| private boolean | isLeapYear(int year)
//REVISIT: should we take care about Julian calendar?
return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
| protected int | maxDayInMonthFor(int year, int month)Given {year,month} computes maximum
number of days for given month
//validate days
if ( month==4 || month==6 || month==9 || month==11 ) {
return 30;
}
else if ( month==2 ) {
if ( isLeapYear(year) ) {
return 29;
}
else {
return 28;
}
}
else {
return 31;
}
| protected int | mod(int a, int b, int quotient)
//modulo(a, b) = a - fQuotient(a,b)*b
return (a - quotient*b) ;
| protected int | modulo(int temp, int low, int high)
//modulo(a - low, high - low) + low
int a = temp - low;
int b = high - low;
return (mod (a, b, fQuotient(a, b)) + low) ;
| protected void | normalize(int[] date, int[] timeZone)If timezone present - normalize dateTime [E Adding durations to dateTimes]
// REVISIT: we have common code in addDuration() for durations
// should consider reorganizing it.
//
//add minutes (from time zone)
int negate = 1;
if (date[utc]=='+") {
negate = -1;
}
if ( DEBUG ) {
System.out.println("==>date[m]"+date[m]);
System.out.println("==>timeZone[mm]" +timeZone[mm]);
}
int temp = date[m] + negate*timeZone[mm];
int carry = fQuotient (temp, 60);
date[m]= mod(temp, 60, carry);
if ( DEBUG ) {
System.out.println("==>carry: " + carry);
}
//add hours
temp = date[h] + negate*timeZone[hh] + carry;
carry = fQuotient(temp, 24);
date[h]=mod(temp, 24, carry);
if ( DEBUG ) {
System.out.println("==>date[h]"+date[h]);
System.out.println("==>carry: " + carry);
}
date[D]=date[D]+carry;
while ( true ) {
temp=maxDayInMonthFor(date[CY], date[M]);
if (date[D]<1) {
date[D] = date[D] + maxDayInMonthFor(date[CY], date[M]-1);
carry=-1;
}
else if ( date[D]>temp ) {
date[D]=date[D]-temp;
carry=1;
}
else {
break;
}
temp=date[M]+carry;
date[M]=modulo(temp, 1, 13);
date[CY]=date[CY]+fQuotient(temp, 1, 13);
}
date[utc]='Z";
| protected int | parseInt(java.lang.String buffer, int start, int end)Given start and end position, parses string value
//REVISIT: more testing on this parsing needs to be done.
int radix=10;
int result = 0;
int digit=0;
int limit = -Integer.MAX_VALUE;
int multmin = limit / radix;
int i = start;
do {
digit = getDigit(buffer.charAt(i));
if ( digit < 0 ) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
if ( result < multmin ) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
result *= radix;
if ( result < limit + digit ) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
result -= digit;
}while ( ++i < end );
return -result;
| protected int | parseIntYear(java.lang.String buffer, int end)
int radix=10;
int result = 0;
boolean negative = false;
int i=0;
int limit;
int multmin;
int digit=0;
if (buffer.charAt(0) == '-"){
negative = true;
limit = Integer.MIN_VALUE;
i++;
}
else{
limit = -Integer.MAX_VALUE;
}
multmin = limit / radix;
while (i < end)
{
digit = getDigit(buffer.charAt(i++));
if (digit < 0) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
if (result < multmin) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
result *= radix;
if (result < limit + digit) throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
result -= digit;
}
if (negative)
{
if (i > 1) return result;
else throw new NumberFormatException("'"+buffer.toString()+"' has wrong format");
}
return -result;
| protected void | parseTimeZone(java.lang.String buffer, int start, int end, int[] date, int[] timeZone)Shared code from Date and YearMonth datatypes.
Finds if time zone sign is present
//fStart points right after the date
if ( start<end ) {
int sign = findUTCSign(buffer, start, end);
if ( sign<0 ) {
throw new RuntimeException ("Error in month parsing");
}
else {
getTimeZone(buffer, date, sign, end, timeZone);
}
}
| protected void | resetDateObj(int[] data)Resets object representation of date/time
for ( int i=0;i<TOTAL_SIZE;i++ ) {
data[i]=0;
}
| protected void | validateDateTime(int[] data, int[] timeZone)Validates given date/time object accoring to W3C PR Schema
[D.1 ISO 8601 Conventions]
//REVISIT: should we throw an exception for not valid dates
// or reporting an error message should be sufficient?
if ( data[CY]==0 ) {
throw new RuntimeException("The year \"0000\" is an illegal year value");
}
if ( data[M]<1 || data[M]>12 ) {
throw new RuntimeException("The month must have values 1 to 12");
}
//validate days
if ( data[D]>maxDayInMonthFor(data[CY], data[M]) || data[D]<1 ) {
throw new RuntimeException("The day must have values 1 to 31");
}
//validate hours
if ( data[h]>23 || data[h]<0 ) {
if (data[h] == 24 && data[m] == 0 && data[s] == 0 && data[ms] == 0) {
data[h] = 0;
if (++data[D] > maxDayInMonthFor(data[CY], data[M])) {
data[D] = 1;
if (++data[M] > 12) {
data[M] = 1;
if (++data[CY] == 0)
data[CY] = 1;
}
}
}
else {
throw new RuntimeException("Hour must have values 0-23, unless 24:00:00");
}
}
//validate
if ( data[m]>59 || data[m]<0 ) {
throw new RuntimeException("Minute must have values 0-59");
}
//validate
if ( data[s]>60 || data[s]<0 ) {
throw new RuntimeException("Second must have values 0-60");
}
//validate
if ( timeZone[hh]>14 || timeZone[hh]<-14 ) {
throw new RuntimeException("Time zone should have range -14..+14");
}
//validate
if ( timeZone[mm]>59 || timeZone[mm]<-59 ) {
throw new RuntimeException("Minute must have values 0-59");
}
|
|