/* * reserved comment block * DO NOT REMOVE OR ALTER! */ /* * Copyright 1999-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.sun.org.apache.xerces.internal.impl.dv.xs; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; import com.sun.org.apache.xerces.internal.impl.Constants; import com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl; import com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime; /** * 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 * * @xerces.internal * * @author Elena Litani * @author Len Berman * @author Gopal Sharma, SUN Microsystems Inc. * * @version $Id: AbstractDateTimeDV.java,v 1.2.6.1 2005/09/06 11:43:00 neerajbj Exp $ */ public abstract class AbstractDateTimeDV extends TypeValidator { //debugging private static final boolean DEBUG=false; //define shared variables for date/time //define constants to be used in assigning default values for //all date/time excluding duration protected final static int YEAR=2000; protected final static int MONTH=01; protected final static int DAY = 01; protected DatatypeFactory factory = new DatatypeFactoryImpl(); 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 ); }//getAllowedFacets() // distinguishes between identity and equality for date/time values // ie: two values representing the same "moment in time" but with different // remembered timezones are now equal but not identical. public boolean isIdentical (Object value1, Object value2) { if (!(value1 instanceof DateTimeData) || !(value2 instanceof DateTimeData)) { return false; } DateTimeData v1 = (DateTimeData)value1; DateTimeData v2 = (DateTimeData)value2; // original timezones must be the same in addition to date/time values // being 'equal' if ((v1.timezoneHr == v2.timezoneHr) && (v1.timezoneMin == v2.timezoneMin)) { return v1.equals(v2); } return false; }//isIdentical() // the parameters are in compiled form (from getActualValue) public int compare (Object value1, Object value2) { return compareDates(((DateTimeData)value1), ((DateTimeData)value2), true); }//compare() /** * Compare algorithm described in dateDime (3.2.7). * Duration datatype overwrites this method * * @param date1 normalized date representation of the first value * @param date2 normalized date representation of the second value * @param strict * @return less, greater, less_equal, greater_equal, equal */ protected short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) { if (date1.utc == date2.utc) { return compareOrder(date1, date2); } short c1, c2; DateTimeData tempDate = new DateTimeData(null, this); if ( date1.utc=='Z' ) { //compare date1<=date1<=(date2 with time zone -14) // cloneDate(date2, tempDate); //clones date1 value to global temporary storage: fTempDate tempDate.timezoneHr=14; tempDate.timezoneMin = 0; tempDate.utc='+'; normalize(tempDate); 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 tempDate.timezoneHr = -14; tempDate.timezoneMin = 0; tempDate.utc='-'; normalize(tempDate); 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 tempDate.timezoneHr = -14; tempDate.timezoneMin = 0; tempDate.utc='-'; if (DEBUG) { System.out.println("tempDate=" + dateToString(tempDate)); } normalize(tempDate); 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 tempDate.timezoneHr = 14; tempDate.timezoneMin = 0; tempDate.utc='+'; normalize(tempDate); c2 = compareOrder(tempDate, date2); if (DEBUG) { System.out.println("tempDate=" + dateToString(tempDate)); } if (c2 == GREATER_THAN) return c2; return INDETERMINATE; } return INDETERMINATE; } /** * Given normalized values, determines order-relation * between give date/time objects. * * @param date1 date/time object * @param date2 date/time object * @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 */ protected short compareOrder(DateTimeData date1, DateTimeData date2) { if(date1.position < 1) { if (date1.year < date2.year) return -1; if (date1.year > date2.year) return 1; } if(date1.position < 2) { if (date1.month < date2.month) return -1; if (date1.month > date2.month) return 1; } if (date1.day < date2.day) return -1; if (date1.day > date2.day) return 1; if (date1.hour < date2.hour) return -1; if (date1.hour > date2.hour) return 1; if (date1.minute < date2.minute) return -1; if (date1.minute > date2.minute) return 1; if (date1.second < date2.second) return -1; if (date1.second > date2.second) return 1; if (date1.utc < date2.utc) return -1; if (date1.utc > date2.utc) return 1; return 0; } /** * Parses time hh:mm:ss.sss and time zone if any * * @param start * @param end * @param data * @exception RuntimeException */ protected void getTime (String buffer, int start, int end, DateTimeData data) throws RuntimeException{ int stop = start+2; //get hours (hh) data.hour=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.minute=parseInt(buffer, start,stop); //get seconds (ss) if (buffer.charAt(stop++)!=':') { throw new RuntimeException("Error in parsing time zone" ); } //find UTC sign if any int sign = findUTCSign(buffer, start, end); //get seconds (ms) start = stop; stop = sign < 0 ? end : sign; data.second = parseSecond(buffer, start, stop); //parse UTC time zone (hh:mm) if (sign > 0) { getTimeZone(buffer, data, sign, end); } } /** * Parses date CCYY-MM-DD * * @param buffer * @param start start position * @param end end position * @param date * @exception RuntimeException */ protected int getDate (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ 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.day=parseInt(buffer, start, stop); return stop; } /** * Parses date CCYY-MM * * @param buffer * @param start start position * @param end end position * @param date * @exception RuntimeException */ protected int getYearMonth (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ 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.year= parseIntYear(buffer, i); if (buffer.charAt(i)!='-') { throw new RuntimeException("CCYY must be followed by '-' sign"); } start = ++i; i = start +2; date.month=parseInt(buffer, start, i); return i; //fStart points right after the MONTH } /** * Shared code from Date and YearMonth datatypes. * Finds if time zone sign is present * * @param end * @param date * @exception RuntimeException */ protected void parseTimeZone (String buffer, int start, int end, DateTimeData date) throws RuntimeException{ //fStart points right after the date if ( start < end ) { if (!isNextCharUTCSign(buffer, start, end)) { throw new RuntimeException ("Error in month parsing"); } else { getTimeZone(buffer, date, start, end); } } } /** * Parses time zone: 'Z' or {+,-} followed by hh:mm * * @param data * @param sign * @exception RuntimeException */ protected void getTimeZone (String buffer, DateTimeData data, int sign, int end) throws RuntimeException{ 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) ) { int negate = buffer.charAt(sign) == '-'?-1:1; //parse hr int stop = ++sign+2; data.timezoneHr = negate*parseInt(buffer, sign, stop); if (buffer.charAt(stop++)!=':') { throw new RuntimeException("Error in parsing time zone" ); } //parse min data.timezoneMin = negate*parseInt(buffer, stop, stop+2); if ( stop+2!=end ) { throw new RuntimeException("Error in parsing time zone"); } if(data.timezoneHr != 0 || data.timezoneMin != 0) data.normalized = false; } else { throw new RuntimeException("Error in parsing time zone"); } if ( DEBUG ) { System.out.println("time[hh]="+data.timezoneHr + " time[mm]=" +data.timezoneMin); } } /** * Computes index of given char within StringBuffer * * @param start * @param end * @param ch character to look for in StringBuffer * @return index of ch within StringBuffer */ protected int indexOf (String buffer, int start, int end, char ch) { for ( int i=start;i<end;i++ ) { if ( buffer.charAt(i) == ch ) { return i; } } return -1; } /** * Validates given date/time object accoring to W3C PR Schema * [D.1 ISO 8601 Conventions] * * @param data */ protected void validateDateTime (DateTimeData data) { //REVISIT: should we throw an exception for not valid dates // or reporting an error message should be sufficient? /** * XML Schema 1.1 - RQ-123: Allow year 0000 in date related types. */ if (!Constants.SCHEMA_1_1_SUPPORT && data.year==0 ) { throw new RuntimeException("The year \"0000\" is an illegal year value"); } if ( data.month<1 || data.month>12 ) { throw new RuntimeException("The month must have values 1 to 12"); } //validate days if ( data.day>maxDayInMonthFor(data.year, data.month) || data.day<1 ) { throw new RuntimeException("The day must have values 1 to 31"); } //validate hours if ( data.hour>23 || data.hour<0 ) { if (data.hour == 24 && data.minute == 0 && data.second == 0) { data.hour = 0; if (++data.day > maxDayInMonthFor(data.year, data.month)) { data.day = 1; if (++data.month > 12) { data.month = 1; if (Constants.SCHEMA_1_1_SUPPORT) { ++data.year; } else if (++data.year == 0) { data.year = 1; } } } } else { throw new RuntimeException("Hour must have values 0-23, unless 24:00:00"); } } //validate if ( data.minute>59 || data.minute<0 ) { throw new RuntimeException("Minute must have values 0-59"); } //validate if ( data.second>=60 || data.second<0 ) { throw new RuntimeException("Second must have values 0-59"); } //validate if ( data.timezoneHr>14 || data.timezoneHr<-14 ) { throw new RuntimeException("Time zone should have range -14:00 to +14:00"); } else { if((data.timezoneHr == 14 || data.timezoneHr == -14) && data.timezoneMin != 0) throw new RuntimeException("Time zone should have range -14:00 to +14:00"); else if(data.timezoneMin > 59 || data.timezoneMin < -59) throw new RuntimeException("Minute must have values 0-59"); } } /** * Return index of UTC char: 'Z', '+', '-' * * @param start * @param end * @return index of the UTC character that was found */ protected int findUTCSign (String buffer, int start, int end) { int c; for ( int i=start;i<end;i++ ) { c=buffer.charAt(i); if ( c == 'Z' || c=='+' || c=='-' ) { return i; } } return -1; } /** * Returns <code>true</code> if the character at start is 'Z', '+' or '-'. */ protected final boolean isNextCharUTCSign(String buffer, int start, int end) { if (start < end) { char c = buffer.charAt(start); return (c == 'Z' || c == '+' || c == '-'); } return false; } /** * Given start and end position, parses string value * * @param buffer string to parse * @param start start position * @param end end position * @return return integer representation of characters */ protected int parseInt (String buffer, int start, int end) throws NumberFormatException{ //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 + "' has wrong format"); if ( result < multmin ) throw new NumberFormatException("'" + buffer + "' has wrong format"); result *= radix; if ( result < limit + digit ) throw new NumberFormatException("'" + buffer + "' has wrong format"); result -= digit; }while ( ++i < end ); return -result; } // parse Year differently to support negative value. protected int parseIntYear (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 + "' has wrong format"); if (result < multmin) throw new NumberFormatException("'" + buffer + "' has wrong format"); result *= radix; if (result < limit + digit) throw new NumberFormatException("'" + buffer + "' has wrong format"); result -= digit; } if (negative) { if (i > 1) return result; else throw new NumberFormatException("'" + buffer + "' has wrong format"); } return -result; } /** * If timezone present - normalize dateTime [E Adding durations to dateTimes] * * @param date CCYY-MM-DDThh:mm:ss+03 * @return CCYY-MM-DDThh:mm:ssZ */ protected void normalize(DateTimeData date) { // REVISIT: we have common code in addDuration() for durations // should consider reorganizing it. // //add minutes (from time zone) int negate = -1; if ( DEBUG ) { System.out.println("==>date.minute"+date.minute); System.out.println("==>date.timezoneMin" +date.timezoneMin); } int temp = date.minute + negate * date.timezoneMin; int carry = fQuotient (temp, 60); date.minute= mod(temp, 60, carry); if ( DEBUG ) { System.out.println("==>carry: " + carry); } //add hours temp = date.hour + negate * date.timezoneHr + carry; carry = fQuotient(temp, 24); date.hour=mod(temp, 24, carry); if ( DEBUG ) { System.out.println("==>date.hour"+date.hour); System.out.println("==>carry: " + carry); } date.day=date.day+carry; while ( true ) { temp=maxDayInMonthFor(date.year, date.month); if (date.day<1) { date.day = date.day + maxDayInMonthFor(date.year, date.month-1); carry=-1; } else if ( date.day>temp ) { date.day=date.day-temp; carry=1; } else { break; } temp=date.month+carry; date.month=modulo(temp, 1, 13); date.year=date.year+fQuotient(temp, 1, 13); if(date.year == 0 && !Constants.SCHEMA_1_1_SUPPORT) { date.year = (date.timezoneHr < 0 || date.timezoneMin < 0)?1:-1; } } date.utc='Z'; } /** * @param date */ protected void saveUnnormalized(DateTimeData date) { date.unNormYear = date.year; date.unNormMonth = date.month; date.unNormDay = date.day; date.unNormHour = date.hour; date.unNormMinute = date.minute; date.unNormSecond = date.second; } /** * Resets object representation of date/time * * @param data date/time object */ protected void resetDateObj(DateTimeData data) { data.year = 0; data.month = 0; data.day = 0; data.hour = 0; data.minute = 0; data.second = 0; data.utc = 0; data.timezoneHr = 0; data.timezoneMin = 0; } /** * Given {year,month} computes maximum * number of days for given month * * @param year * @param month * @return integer containg the number of days in a given month */ protected int maxDayInMonthFor(int year, int 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; } } private boolean isLeapYear(int year) { //REVISIT: should we take care about Julian calendar? return((year%4 == 0) && ((year%100 != 0) || (year%400 == 0))); } // // help function described in W3C PR Schema [E Adding durations to dateTimes] // protected int mod (int a, int b, int quotient) { //modulo(a, b) = a - fQuotient(a,b)*b return (a - quotient*b) ; } // // help function described in W3C PR Schema [E Adding durations to dateTimes] // 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); } // // help function described in W3C PR Schema [E Adding durations to dateTimes] // 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) ; } // // help function described in W3C PR Schema [E Adding durations to dateTimes] // protected int fQuotient (int temp, int low, int high) { //fQuotient(a - low, high - low) return fQuotient(temp - low, high - low); } protected String dateToString(DateTimeData date) { StringBuffer message = new StringBuffer(25); append(message, date.year, 4); message.append('-'); append(message, date.month, 2); message.append('-'); append(message, date.day, 2); message.append('T'); append(message, date.hour, 2); message.append(':'); append(message, date.minute, 2); message.append(':'); append(message, date.second); append(message, (char)date.utc, 0); return message.toString(); } protected void append(StringBuffer message, int value, int nch) { if (value == Integer.MIN_VALUE) { message.append(value); return; } 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); } } protected void append(StringBuffer message, double value) { if (value < 0) { message.append('-'); value = -value; } if (value < 10) message.append('0'); message.append(value); } protected double parseSecond(String buffer, int start, int end) throws NumberFormatException { int dot = -1; for (int i = start; i < end; i++) { char ch = buffer.charAt(i); if (ch == '.') dot = i; else if (ch > '9' || ch < '0') throw new NumberFormatException("'" + buffer + "' has wrong format"); } if (dot == -1) { if (start+2 != end) throw new NumberFormatException("'" + buffer + "' has wrong format"); } else if (start+2 != dot || dot+1 == end) { throw new NumberFormatException("'" + buffer + "' has wrong format"); } return Double.parseDouble(buffer.substring(start, end)); } // //Private help functions // private void cloneDate (DateTimeData finalValue, DateTimeData tempDate) { tempDate.year = finalValue.year; tempDate.month = finalValue.month; tempDate.day = finalValue.day; tempDate.hour = finalValue.hour; tempDate.minute = finalValue.minute; tempDate.second = finalValue.second; tempDate.utc = finalValue.utc; tempDate.timezoneHr = finalValue.timezoneHr; tempDate.timezoneMin = finalValue.timezoneMin; } /** * Represents date time data */ static final class DateTimeData implements XSDateTime { int year, month, day, hour, minute, utc; double second; int timezoneHr, timezoneMin; private String originalValue; boolean normalized = true; int unNormYear; int unNormMonth; int unNormDay; int unNormHour; int unNormMinute; double unNormSecond; // used for comparisons - to decide the 'interesting' portions of // a date/time based data type. int position; // a pointer to the type that was used go generate this data // note that this is not the actual simple type, but one of the // statically created XXXDV objects, so this won't cause any GC problem. final AbstractDateTimeDV type; private String canonical; public DateTimeData(String originalValue, AbstractDateTimeDV type) { this.originalValue = originalValue; this.type = type; } public DateTimeData(int year, int month, int day, int hour, int minute, double second, int utc, String originalValue, boolean normalized, AbstractDateTimeDV type) { this.year = year; this.month = month; this.day = day; this.hour = hour; this.minute = minute; this.second = second; this.utc = utc; this.type = type; this.originalValue = originalValue; } public boolean equals(Object obj) { if (!(obj instanceof DateTimeData)) return false; return type.compareDates(this, (DateTimeData)obj, true)==0; } public synchronized String toString() { if (canonical == null) { canonical = type.dateToString(this); } return canonical; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getYear() */ public int getYears() { if(type instanceof DurationDV) return 0; return normalized?year:unNormYear; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getMonth() */ public int getMonths() { if(type instanceof DurationDV) { return year*12 + month; } return normalized?month:unNormMonth; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getDay() */ public int getDays() { if(type instanceof DurationDV) return 0; return normalized?day:unNormDay; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getHour() */ public int getHours() { if(type instanceof DurationDV) return 0; return normalized?hour:unNormHour; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getMinutes() */ public int getMinutes() { if(type instanceof DurationDV) return 0; return normalized?minute:unNormMinute; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getSeconds() */ public double getSeconds() { if(type instanceof DurationDV) { return day*24*60*60 + hour*60*60 + minute*60 + second; } return normalized?second:unNormSecond; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#hasTimeZone() */ public boolean hasTimeZone() { return utc != 0; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getTimeZoneHours() */ public int getTimeZoneHours() { return timezoneHr; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getTimeZoneMinutes() */ public int getTimeZoneMinutes() { return timezoneMin; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getLexicalValue() */ public String getLexicalValue() { return originalValue; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#normalize() */ public XSDateTime normalize() { if(!normalized) { DateTimeData dt = (DateTimeData)this.clone(); dt.normalized = true; return dt; } return this; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#isNormalized() */ public boolean isNormalized() { return normalized; } public Object clone() { DateTimeData dt = new DateTimeData(this.year, this.month, this.day, this.hour, this.minute, this.second, this.utc, this.originalValue, this.normalized, this.type); dt.canonical = this.canonical; dt.position = position; dt.timezoneHr = this.timezoneHr; dt.timezoneMin = this.timezoneMin; dt.unNormYear = this.unNormYear; dt.unNormMonth = this.unNormMonth; dt.unNormDay = this.unNormDay; dt.unNormHour = this.unNormHour; dt.unNormMinute = this.unNormMinute; dt.unNormSecond = this.unNormSecond; return dt; } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getXMLGregorianCalendar() */ public XMLGregorianCalendar getXMLGregorianCalendar() { return type.getXMLGregorianCalendar(this); } /* (non-Javadoc) * @see com.sun.org.apache.xerces.internal.xs.datatypes.XSDateTime#getDuration() */ public Duration getDuration() { return type.getDuration(this); } } protected XMLGregorianCalendar getXMLGregorianCalendar(DateTimeData data) { return null; } protected Duration getDuration(DateTimeData data) { return null; } }