KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > dv > xs > AbstractDateTimeDV


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl.dv.xs;
18
19 import javax.xml.datatype.DatatypeFactory JavaDoc;
20 import javax.xml.datatype.Duration JavaDoc;
21 import javax.xml.datatype.XMLGregorianCalendar JavaDoc;
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 /**
28  * This is the base class of all date/time datatype validators.
29  * It implements common code for parsing, validating and comparing datatypes.
30  * Classes that extend this class, must implement parse() method.
31  *
32  * REVISIT: There are many instance variables, which would cause problems
33  * when we support grammar caching. A grammar is possibly used by
34  * two parser instances at the same time, then the same simple type
35  * decl object can be used to validate two strings at the same time.
36  * -SG
37  *
38  * @xerces.internal
39  *
40  * @author Elena Litani
41  * @author Len Berman
42  * @author Gopal Sharma, SUN Microsystems Inc.
43  *
44  * @version $Id: AbstractDateTimeDV.java,v 1.40 2005/07/19 04:32:40 mrglavas Exp $
45  */

46 public abstract class AbstractDateTimeDV extends TypeValidator {
47     
48     //debugging
49
private static final boolean DEBUG=false;
50     
51     //define shared variables for date/time
52

53     
54     //define constants to be used in assigning default values for
55
//all date/time excluding duration
56
protected final static int YEAR=2000;
57     protected final static int MONTH=01;
58     protected final static int DAY = 01;
59     
60     protected DatatypeFactory JavaDoc 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     }//getAllowedFacets()
65

66     
67     // distinguishes between identity and equality for date/time values
68
// ie: two values representing the same "moment in time" but with different
69
// remembered timezones are now equal but not identical.
70
public boolean isIdentical (Object JavaDoc value1, Object JavaDoc 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         // original timezones must be the same in addition to date/time values
79
// being 'equal'
80
if ((v1.timezoneHr == v2.timezoneHr) && (v1.timezoneMin == v2.timezoneMin)) {
81             return v1.equals(v2);
82         }
83         
84         return false;
85     }//isIdentical()
86

87     // the parameters are in compiled form (from getActualValue)
88
public int compare (Object JavaDoc value1, Object JavaDoc value2) {
89         return compareDates(((DateTimeData)value1),
90                 ((DateTimeData)value2), true);
91     }//compare()
92

93     /**
94      * Compare algorithm described in dateDime (3.2.7).
95      * Duration datatype overwrites this method
96      *
97      * @param date1 normalized date representation of the first value
98      * @param date2 normalized date representation of the second value
99      * @param strict
100      * @return less, greater, less_equal, greater_equal, equal
101      */

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             //compare date1<=date1<=(date2 with time zone -14)
113
//
114
cloneDate(date2, tempDate); //clones date1 value to global temporary storage: fTempDate
115
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             //compare date1>=(date2 with time zone +14)
124
//
125
cloneDate(date2, tempDate); //clones date1 value to global temporary storage: tempDate
126
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             //compare (date1 with time zone -14)<=date2
139
//
140
cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate
141
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             //compare (date1 with time zone +14)<=date2
157
//
158
cloneDate(date1, tempDate); //clones date1 value to global temporary storage: tempDate
159
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     /**
177      * Given normalized values, determines order-relation
178      * between give date/time objects.
179      *
180      * @param date1 date/time object
181      * @param date2 date/time object
182      * @return 0 if date1 and date2 are equal, a value less than 0 if date1 is less than date2, a value greater than 0 if date1 is greater than date2
183      */

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     /**
221      * Parses time hh:mm:ss.sss and time zone if any
222      *
223      * @param start
224      * @param end
225      * @param data
226      * @exception RuntimeException
227      */

228     protected void getTime (String JavaDoc buffer, int start, int end, DateTimeData data) throws RuntimeException JavaDoc{
229         
230         int stop = start+2;
231         
232         //get hours (hh)
233
data.hour=parseInt(buffer, start,stop);
234         
235         //get minutes (mm)
236

237         if (buffer.charAt(stop++)!=':') {
238             throw new RuntimeException JavaDoc("Error in parsing time zone" );
239         }
240         start = stop;
241         stop = stop+2;
242         data.minute=parseInt(buffer, start,stop);
243         
244         //get seconds (ss)
245
if (buffer.charAt(stop++)!=':') {
246             throw new RuntimeException JavaDoc("Error in parsing time zone" );
247         }
248         
249         //find UTC sign if any
250
int sign = findUTCSign(buffer, start, end);
251         
252         //get seconds (ms)
253
start = stop;
254         stop = sign < 0 ? end : sign;
255         data.second = parseSecond(buffer, start, stop);
256         
257         //parse UTC time zone (hh:mm)
258
if (sign > 0) {
259             getTimeZone(buffer, data, sign, end);
260         }
261     }
262     
263     /**
264      * Parses date CCYY-MM-DD
265      *
266      * @param buffer
267      * @param start start position
268      * @param end end position
269      * @param date
270      * @exception RuntimeException
271      */

272     protected int getDate (String JavaDoc buffer, int start, int end, DateTimeData date) throws RuntimeException JavaDoc{
273         
274         start = getYearMonth(buffer, start, end, date);
275         
276         if (buffer.charAt(start++) !='-') {
277             throw new RuntimeException JavaDoc("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     /**
285      * Parses date CCYY-MM
286      *
287      * @param buffer
288      * @param start start position
289      * @param end end position
290      * @param date
291      * @exception RuntimeException
292      */

293     protected int getYearMonth (String JavaDoc buffer, int start, int end, DateTimeData date) throws RuntimeException JavaDoc{
294         
295         if ( buffer.charAt(0)=='-' ) {
296             // REVISIT: date starts with preceding '-' sign
297
// do we have to do anything with it?
298
//
299
start++;
300         }
301         int i = indexOf(buffer, start, end, '-');
302         if ( i==-1 ) throw new RuntimeException JavaDoc("Year separator is missing or misplaced");
303         int length = i-start;
304         if (length<4) {
305             throw new RuntimeException JavaDoc("Year must have 'CCYY' format");
306         }
307         else if (length > 4 && buffer.charAt(start)=='0'){
308             throw new RuntimeException JavaDoc("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 JavaDoc("CCYY must be followed by '-' sign");
313         }
314         start = ++i;
315         i = start +2;
316         date.month=parseInt(buffer, start, i);
317         return i; //fStart points right after the MONTH
318
}
319     
320     /**
321      * Shared code from Date and YearMonth datatypes.
322      * Finds if time zone sign is present
323      *
324      * @param end
325      * @param date
326      * @exception RuntimeException
327      */

328     protected void parseTimeZone (String JavaDoc buffer, int start, int end, DateTimeData date) throws RuntimeException JavaDoc{
329         
330         //fStart points right after the date
331

332         if ( start < end ) {
333             if (!isNextCharUTCSign(buffer, start, end)) {
334                 throw new RuntimeException JavaDoc ("Error in month parsing");
335             }
336             else {
337                 getTimeZone(buffer, date, start, end);
338             }
339         }
340     }
341     
342     /**
343      * Parses time zone: 'Z' or {+,-} followed by hh:mm
344      *
345      * @param data
346      * @param sign
347      * @exception RuntimeException
348      */

349     protected void getTimeZone (String JavaDoc buffer, DateTimeData data, int sign, int end) throws RuntimeException JavaDoc{
350         data.utc=buffer.charAt(sign);
351         
352         if ( buffer.charAt(sign) == 'Z' ) {
353             if (end>(++sign)) {
354                 throw new RuntimeException JavaDoc("Error in parsing time zone");
355             }
356             return;
357         }
358         if ( sign<=(end-6) ) {
359             
360             int negate = buffer.charAt(sign) == '-'?-1:1;
361             //parse hr
362
int stop = ++sign+2;
363             data.timezoneHr = negate*parseInt(buffer, sign, stop);
364             if (buffer.charAt(stop++)!=':') {
365                 throw new RuntimeException JavaDoc("Error in parsing time zone" );
366             }
367             
368             //parse min
369
data.timezoneMin = negate*parseInt(buffer, stop, stop+2);
370             
371             if ( stop+2!=end ) {
372                 throw new RuntimeException JavaDoc("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 JavaDoc("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     /**
386      * Computes index of given char within StringBuffer
387      *
388      * @param start
389      * @param end
390      * @param ch character to look for in StringBuffer
391      * @return index of ch within StringBuffer
392      */

393     protected int indexOf (String JavaDoc 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     /**
403      * Validates given date/time object accoring to W3C PR Schema
404      * [D.1 ISO 8601 Conventions]
405      *
406      * @param data
407      */

408     protected void validateDateTime (DateTimeData data) {
409         
410         //REVISIT: should we throw an exception for not valid dates
411
// or reporting an error message should be sufficient?
412

413         /**
414          * XML Schema 1.1 - RQ-123: Allow year 0000 in date related types.
415          */

416         if (!Constants.SCHEMA_1_1_SUPPORT && data.year==0 ) {
417             throw new RuntimeException JavaDoc("The year \"0000\" is an illegal year value");
418             
419         }
420         
421         if ( data.month<1 || data.month>12 ) {
422             throw new RuntimeException JavaDoc("The month must have values 1 to 12");
423             
424         }
425         
426         //validate days
427
if ( data.day>maxDayInMonthFor(data.year, data.month) || data.day<1 ) {
428             throw new RuntimeException JavaDoc("The day must have values 1 to 31");
429         }
430         
431         //validate hours
432
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 JavaDoc("Hour must have values 0-23, unless 24:00:00");
450             }
451         }
452         
453         //validate
454
if ( data.minute>59 || data.minute<0 ) {
455             throw new RuntimeException JavaDoc("Minute must have values 0-59");
456         }
457         
458         //validate
459
if ( data.second>=60 || data.second<0 ) {
460             throw new RuntimeException JavaDoc("Second must have values 0-59");
461             
462         }
463         
464         //validate
465
if ( data.timezoneHr>14 || data.timezoneHr<-14 ) {
466             throw new RuntimeException JavaDoc("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 JavaDoc("Time zone should have range -14:00 to +14:00");
471             else if(data.timezoneMin > 59 || data.timezoneMin < -59)
472                 throw new RuntimeException JavaDoc("Minute must have values 0-59");
473         }
474         
475     }
476     
477     /**
478      * Return index of UTC char: 'Z', '+', '-'
479      *
480      * @param start
481      * @param end
482      * @return index of the UTC character that was found
483      */

484     protected int findUTCSign (String JavaDoc 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     /**
497      * Returns <code>true</code> if the character at start is 'Z', '+' or '-'.
498      */

499     protected final boolean isNextCharUTCSign(String JavaDoc 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     /**
508      * Given start and end position, parses string value
509      *
510      * @param buffer string to parse
511      * @param start start position
512      * @param end end position
513      * @return return integer representation of characters
514      */

515     protected int parseInt (String JavaDoc buffer, int start, int end)
516     throws NumberFormatException JavaDoc{
517         //REVISIT: more testing on this parsing needs to be done.
518
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 JavaDoc("'" + buffer + "' has wrong format");
527             if ( result < multmin ) throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
528             result *= radix;
529             if ( result < limit + digit ) throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
530             result -= digit;
531             
532         }while ( ++i < end );
533         return -result;
534     }
535     
536     // parse Year differently to support negative value.
537
protected int parseIntYear (String JavaDoc 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 JavaDoc("'" + buffer + "' has wrong format");
560             if (result < multmin) throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
561             result *= radix;
562             if (result < limit + digit) throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
563             result -= digit;
564         }
565         
566         if (negative)
567         {
568             if (i > 1) return result;
569             else throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
570         }
571         return -result;
572         
573     }
574     
575     /**
576      * If timezone present - normalize dateTime [E Adding durations to dateTimes]
577      *
578      * @param date CCYY-MM-DDThh:mm:ss+03
579      * @return CCYY-MM-DDThh:mm:ssZ
580      */

581     protected void normalize(DateTimeData date) {
582         
583         // REVISIT: we have common code in addDuration() for durations
584
// should consider reorganizing it.
585
//
586

587         //add minutes (from time zone)
588
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         //add hours
602
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     /**
637      * @param date
638      */

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     /**
649      * Resets object representation of date/time
650      *
651      * @param data date/time object
652      */

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     /**
666      * Given {year,month} computes maximum
667      * number of days for given month
668      *
669      * @param year
670      * @param month
671      * @return integer containg the number of days in a given month
672      */

673     protected int maxDayInMonthFor(int year, int month) {
674         //validate days
675
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         //REVISIT: should we take care about Julian calendar?
694
return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0)));
695     }
696     
697     //
698
// help function described in W3C PR Schema [E Adding durations to dateTimes]
699
//
700
protected int mod (int a, int b, int quotient) {
701         //modulo(a, b) = a - fQuotient(a,b)*b
702
return (a - quotient*b) ;
703     }
704     
705     //
706
// help function described in W3C PR Schema [E Adding durations to dateTimes]
707
//
708
protected int fQuotient (int a, int b) {
709         
710         //fQuotient(a, b) = the greatest integer less than or equal to a/b
711
return (int)Math.floor((float)a/b);
712     }
713     
714     //
715
// help function described in W3C PR Schema [E Adding durations to dateTimes]
716
//
717
protected int modulo (int temp, int low, int high) {
718         //modulo(a - low, high - low) + low
719
int a = temp - low;
720         int b = high - low;
721         return (mod (a, b, fQuotient(a, b)) + low) ;
722     }
723     
724     //
725
// help function described in W3C PR Schema [E Adding durations to dateTimes]
726
//
727
protected int fQuotient (int temp, int low, int high) {
728         //fQuotient(a - low, high - low)
729

730         return fQuotient(temp - low, high - low);
731     }
732     
733     
734     protected String JavaDoc dateToString(DateTimeData date) {
735         StringBuffer JavaDoc message = new StringBuffer JavaDoc(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 JavaDoc 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 JavaDoc 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 JavaDoc buffer, int start, int end)
791     throws NumberFormatException JavaDoc {
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 JavaDoc("'" + buffer + "' has wrong format");
799         }
800         if (dot == -1) {
801             if (start+2 != end)
802                 throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
803         }
804         else if (start+2 != dot || dot+1 == end) {
805             throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
806         }
807         return Double.parseDouble(buffer.substring(start, end));
808     }
809     
810     //
811
//Private help functions
812
//
813

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     /**
827      * Represents date time data
828      */

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 JavaDoc 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         // used for comparisons - to decide the 'interesting' portions of
844
// a date/time based data type.
845
int position;
846         // a pointer to the type that was used go generate this data
847
// note that this is not the actual simple type, but one of the
848
// statically created XXXDV objects, so this won't cause any GC problem.
849
final AbstractDateTimeDV type;
850         private String JavaDoc canonical;
851         public DateTimeData(String JavaDoc 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 JavaDoc 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 JavaDoc obj) {
868             if (!(obj instanceof DateTimeData))
869                 return false;
870             return type.compareDates(this, (DateTimeData)obj, true)==0;
871         }
872         public synchronized String JavaDoc toString() {
873             if (canonical == null) {
874                 canonical = type.dateToString(this);
875             }
876             return canonical;
877         }
878         /* (non-Javadoc)
879          * @see org.apache.xerces.xs.datatypes.XSDateTime#getYear()
880          */

881         public int getYears() {
882             if(type instanceof DurationDV)
883                 return 0;
884             return normalized?year:unNormYear;
885         }
886         /* (non-Javadoc)
887          * @see org.apache.xerces.xs.datatypes.XSDateTime#getMonth()
888          */

889         public int getMonths() {
890             if(type instanceof DurationDV) {
891                 return year*12 + month;
892             }
893             return normalized?month:unNormMonth;
894         }
895         /* (non-Javadoc)
896          * @see org.apache.xerces.xs.datatypes.XSDateTime#getDay()
897          */

898         public int getDays() {
899             if(type instanceof DurationDV)
900                 return 0;
901             return normalized?day:unNormDay;
902         }
903         /* (non-Javadoc)
904          * @see org.apache.xerces.xs.datatypes.XSDateTime#getHour()
905          */

906         public int getHours() {
907             if(type instanceof DurationDV)
908                 return 0;
909             return normalized?hour:unNormHour;
910         }
911         /* (non-Javadoc)
912          * @see org.apache.xerces.xs.datatypes.XSDateTime#getMinutes()
913          */

914         public int getMinutes() {
915             if(type instanceof DurationDV)
916                 return 0;
917             return normalized?minute:unNormMinute;
918         }
919         /* (non-Javadoc)
920          * @see org.apache.xerces.xs.datatypes.XSDateTime#getSeconds()
921          */

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         /* (non-Javadoc)
929          * @see org.apache.xerces.xs.datatypes.XSDateTime#hasTimeZone()
930          */

931         public boolean hasTimeZone() {
932             return utc != 0;
933         }
934         /* (non-Javadoc)
935          * @see org.apache.xerces.xs.datatypes.XSDateTime#getTimeZoneHours()
936          */

937         public int getTimeZoneHours() {
938             return timezoneHr;
939         }
940         /* (non-Javadoc)
941          * @see org.apache.xerces.xs.datatypes.XSDateTime#getTimeZoneMinutes()
942          */

943         public int getTimeZoneMinutes() {
944             return timezoneMin;
945         }
946         /* (non-Javadoc)
947          * @see org.apache.xerces.xs.datatypes.XSDateTime#getLexicalValue()
948          */

949         public String JavaDoc getLexicalValue() {
950             return originalValue;
951         }
952         /* (non-Javadoc)
953          * @see org.apache.xerces.xs.datatypes.XSDateTime#normalize()
954          */

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         /* (non-Javadoc)
964          * @see org.apache.xerces.xs.datatypes.XSDateTime#isNormalized()
965          */

966         public boolean isNormalized() {
967             return normalized;
968         }
969         
970         public Object JavaDoc 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         /* (non-Javadoc)
987          * @see org.apache.xerces.xs.datatypes.XSDateTime#getXMLGregorianCalendar()
988          */

989         public XMLGregorianCalendar JavaDoc getXMLGregorianCalendar() {
990             return type.getXMLGregorianCalendar(this);
991         }
992         /* (non-Javadoc)
993          * @see org.apache.xerces.xs.datatypes.XSDateTime#getDuration()
994          */

995         public Duration JavaDoc getDuration() {
996             return type.getDuration(this);
997         }
998     }
999
1000    protected XMLGregorianCalendar JavaDoc getXMLGregorianCalendar(DateTimeData data) {
1001        return null;
1002    }
1003
1004
1005    protected Duration JavaDoc getDuration(DateTimeData data) {
1006        return null;
1007    }
1008}
1009
Popular Tags