jaxp/src/com/sun/org/apache/xerces/internal/jaxp/datatype/XMLGregorianCalendarImpl.java

Print this page




   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.org.apache.xerces.internal.jaxp.datatype;
  27 


  28 import java.io.Serializable;
  29 import java.math.BigDecimal;
  30 import java.math.BigInteger;
  31 import java.util.TimeZone;
  32 import java.util.Calendar;
  33 import java.util.GregorianCalendar;
  34 import java.util.Date;
  35 import java.util.Locale;
  36 
  37 import javax.xml.datatype.DatatypeConstants;
  38 import javax.xml.datatype.Duration;
  39 import javax.xml.datatype.XMLGregorianCalendar;
  40 import javax.xml.namespace.QName;
  41 import com.sun.org.apache.xerces.internal.util.DatatypeMessageFormatter;
  42 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
  43 
  44 /**
  45  * <p>Representation for W3C XML Schema 1.0 date/time datatypes.
  46  * Specifically, these date/time datatypes are
  47  * {@link DatatypeConstants#DATETIME dateTime},


 178  *   <li>partial order relation comparator method, {@link #compare(XMLGregorianCalendar)}</li>
 179  *   <li>{@link #equals(Object)} defined relative to {@link #compare(XMLGregorianCalendar)}.</li>
 180  *   <li> addition operation with {@link javax.xml.datatype.Duration}.
 181  * instance as defined in <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">
 182  * W3C XML Schema 1.0 Part 2, Appendix E, <i>Adding durations to dateTimes</i></a>.</li>
 183  * </ul>
 184  * </p>
 185  *
 186  * @author <a href="mailto:Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
 187  * @author <a href="mailto:Joseph.Fialli@Sun.com">Joseph Fialli</a>
 188  * @author <a href="mailto:Sunitha.Reddy@Sun.com">Sunitha Reddy</a>
 189  * @version $Revision: 1.14 $, $Date: 2010-11-10 07:41:41 $
 190  * @see javax.xml.datatype.Duration
 191  * @since 1.5
 192  */
 193 
 194 public class XMLGregorianCalendarImpl
 195         extends XMLGregorianCalendar
 196         implements Serializable, Cloneable {
 197 











 198     /**
 199      * <p>Eon of this <code>XMLGregorianCalendar</code>.</p>
 200      */
 201     private BigInteger eon = null;
 202 
 203     /**
 204      * <p>Year of this <code>XMLGregorianCalendar</code>.</p>
 205      */
 206     private int year = DatatypeConstants.FIELD_UNDEFINED;
 207 
 208     /**
 209      * <p>Month of this <code>XMLGregorianCalendar</code>.</p>
 210      */
 211     private int month = DatatypeConstants.FIELD_UNDEFINED;
 212 
 213     /**
 214      * <p>Day of this <code>XMLGregorianCalendar</code>.</p>
 215      */
 216     private int day = DatatypeConstants.FIELD_UNDEFINED;
 217 


 224      * <p>Hour of this <code>XMLGregorianCalendar</code>.</p>
 225      */
 226     private int hour = DatatypeConstants.FIELD_UNDEFINED;
 227 
 228     /**
 229      * <p>Minute of this <code>XMLGregorianCalendar</code>.</p>
 230      */
 231     private int minute = DatatypeConstants.FIELD_UNDEFINED;
 232 
 233     /**
 234      * <p>Second of this <code>XMLGregorianCalendar</code>.</p>
 235      */
 236     private int second = DatatypeConstants.FIELD_UNDEFINED ;
 237 
 238     /**
 239      * <p>Fractional second of this <code>XMLGregorianCalendar</code>.</p>
 240      */
 241     private BigDecimal fractionalSecond = null;
 242 
 243     /**
 244      * <p>Constant to represent a billion.</p>
 245      */
 246     private static final BigInteger BILLION = new BigInteger("1000000000");
 247 
 248     /**





 249      *   <p>Obtain a pure Gregorian Calendar by calling
 250      *   GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE). </p>
 251      */
 252     private static final Date PURE_GREGORIAN_CHANGE =
 253         new Date(Long.MIN_VALUE);
 254 
 255     /**
 256      * Year index for MIN_ and MAX_FIELD_VALUES.
 257      */
 258     private static final int YEAR   = 0;
 259 
 260     /**
 261      * Month index for MIN_ and MAX_FIELD_VALUES.
 262      */
 263     private static final int MONTH  = 1;
 264 
 265     /**
 266      * Day index for MIN_ and MAX_FIELD_VALUES.
 267      */
 268     private static final int DAY    = 2;


 424                 format = "%Y" + "%z";
 425             } else if (countSeparator == 1) {
 426                 // GYearMonth
 427                 format = "%Y-%M" + "%z";
 428             } else {
 429                 // Date or invalid lexicalRepresentation
 430                 // Fix 4971612: invalid SCCS macro substitution in data string
 431                 format = "%Y-%M-%D" + "%z";
 432             }
 433         }
 434         Parser p = new Parser(format, lexRep);
 435         p.parse();
 436 
 437         // check for validity
 438         if (!isValid()) {
 439             throw new IllegalArgumentException(
 440                     DatatypeMessageFormatter.formatMessage(null, "InvalidXGCRepresentation", new Object[]{lexicalRepresentation})
 441                     //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value."
 442             );
 443         }


 444     }
 445 
 446     /**















 447      * <p>Create an instance with all date/time datatype fields set to
 448      * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.</p>
 449      */
 450     public XMLGregorianCalendarImpl() {
 451 
 452         // field initializers already do the correct initialization.
 453     }
 454 
 455     /**
 456      * <p>Private constructor allowing for complete value spaces allowed by
 457      * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
 458      * builtin datatypes. Note that <code>year</code> parameter supports
 459      * arbitrarily large numbers and fractionalSecond has infinite
 460      * precision.</p>
 461      *
 462      * @param year of <code>XMLGregorianCalendar</code> to be created.
 463      * @param month of <code>XMLGregorianCalendar</code> to be created.
 464      * @param day of <code>XMLGregorianCalendar</code> to be created.
 465      * @param hour of <code>XMLGregorianCalendar</code> to be created.
 466      * @param minute of <code>XMLGregorianCalendar</code> to be created.


 504                 String fractionalSecondString = "null";
 505                 if (fractionalSecond != null) {
 506                     fractionalSecondString = fractionalSecond.toString();
 507                 }
 508 
 509                 throw new IllegalArgumentException(
 510                     "year = " + yearString
 511                     + ", month = " + month
 512                     + ", day = " + day
 513                     + ", hour = " + hour
 514                     + ", minute = " + minute
 515                     + ", second = " + second
 516                     + ", fractionalSecond = " + fractionalSecondString
 517                     + ", timezone = " + timezone
 518                     + ", is not a valid representation of an XML Gregorian Calendar value."
 519                 );
 520                 */
 521 
 522                 }
 523 

 524     }
 525 
 526     /**
 527      * <p>Private constructor of value spaces that a
 528      * <code>java.util.GregorianCalendar</code> instance would need to convert to an
 529      * <code>XMLGregorianCalendar</code> instance.</p>
 530      *
 531      * <p><code>XMLGregorianCalendar eon</code> and
 532      * <code>fractionalSecond</code> are set to <code>null</code></p>
 533      *
 534      * @param year of <code>XMLGregorianCalendar</code> to be created.
 535      * @param month of <code>XMLGregorianCalendar</code> to be created.
 536      * @param day of <code>XMLGregorianCalendar</code> to be created.
 537      * @param hour of <code>XMLGregorianCalendar</code> to be created.
 538      * @param minute of <code>XMLGregorianCalendar</code> to be created.
 539      * @param second of <code>XMLGregorianCalendar</code> to be created.
 540      * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
 541      * @param timezone of <code>XMLGregorianCalendar</code> to be created.
 542      */
 543     private XMLGregorianCalendarImpl(
 544         int year,
 545         int month,
 546         int day,
 547         int hour,
 548         int minute,
 549         int second,
 550                 int millisecond,
 551         int timezone) {
 552 
 553                 setYear(year);
 554         setMonth(month);
 555         setDay(day);
 556         setTime(hour, minute, second);
 557                 setTimezone(timezone);
 558                 setMillisecond(millisecond);




 559 
 560                 if (!isValid()) {
 561 
 562             throw new IllegalArgumentException(
 563                 DatatypeMessageFormatter.formatMessage(null,
 564                 "InvalidXGCValue-milli",
 565                 new Object[] { new Integer(year), new Integer(month), new Integer(day),
 566                 new Integer(hour), new Integer(minute), new Integer(second),
 567                 new Integer(millisecond), new Integer(timezone)})
 568                         );
 569                 /*
 570                 throw new IllegalArgumentException(
 571                     "year = " + year
 572                     + ", month = " + month
 573                     + ", day = " + day
 574                     + ", hour = " + hour
 575                     + ", minute = " + minute
 576                     + ", second = " + second
 577                     + ", millisecond = " + millisecond
 578                     + ", timezone = " + timezone
 579                     + ", is not a valid representation of an XML Gregorian Calendar value."
 580                     );
 581                  */
 582 
 583                 }


 584     }
 585 
 586         /**
 587          * <p>Convert a <code>java.util.GregorianCalendar</code> to XML Schema 1.0
 588          * representation.</p>
 589          *
 590          * <table border="2" rules="all" cellpadding="2">
 591          *   <thead>
 592          *     <tr>
 593          *       <th align="center" colspan="2">
 594          *          Field by Field Conversion from
 595          *          <code>java.util.GregorianCalendar</code> to this class
 596          *       </th>
 597          *     </tr>
 598          *   </thead>
 599          *   <tbody>
 600          *     <tr>
 601          *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
 602          *        <th><code>java.util.GregorianCalendar</code> field</th>
 603          *     </tr>


 644 
 645         int year = cal.get(Calendar.YEAR);
 646         if (cal.get(Calendar.ERA) == GregorianCalendar.BC) {
 647             year = -year;
 648         }
 649         this.setYear(year);
 650 
 651         // Calendar.MONTH is zero based, XSD Date datatype's month field starts
 652         // with JANUARY as 1.
 653         this.setMonth(cal.get(Calendar.MONTH) + 1);
 654         this.setDay(cal.get(Calendar.DAY_OF_MONTH));
 655         this.setTime(
 656                 cal.get(Calendar.HOUR_OF_DAY),
 657                 cal.get(Calendar.MINUTE),
 658                 cal.get(Calendar.SECOND),
 659                 cal.get(Calendar.MILLISECOND));
 660 
 661         // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds.
 662         int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
 663         this.setTimezone(offsetInMinutes);

 664     }
 665 
 666     // Factories
 667 
 668     /**
 669      * <p>Create a Java representation of XML Schema builtin datatype <code>dateTime</code>.
 670      * All possible fields are specified for this factory method.</p>
 671      *
 672      * @param year represents both high-order eons and low-order year.
 673      * @param month of <code>dateTime</code>
 674      * @param day of <code>dateTime</code>
 675      * @param hours of <code>dateTime</code>
 676      * @param minutes of <code>dateTime</code>
 677      * @param seconds of <code>dateTime</code>
 678      * @param fractionalSecond value of null indicates optional field is absent.
 679      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 680      *
 681      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 682      *
 683      * @see DatatypeConstants#FIELD_UNDEFINED


1147     }
1148 
1149     // setters
1150 
1151     /**
1152      * <p>Set low and high order component of XSD <code>dateTime</code> year field.</p>
1153      *
1154      * <p>Unset this field by invoking the setter with a parameter value of <code>null</code>.</p>
1155      *
1156      * @param year value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1157      *
1158      * @throws IllegalArgumentException if <code>year</code> parameter is
1159      * outside value constraints for the field as specified in
1160      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1161      */
1162     public void setYear(BigInteger year) {
1163         if (year == null) {
1164             this.eon = null;
1165             this.year = DatatypeConstants.FIELD_UNDEFINED;
1166         } else {
1167             BigInteger temp = year.remainder(BILLION);
1168             this.year = temp.intValue();
1169             setEon(year.subtract(temp));
1170         }
1171     }
1172 
1173     /**
1174      * <p>Set year of XSD <code>dateTime</code> year field.</p>
1175      *
1176      * <p>Unset this field by invoking the setter with a parameter value of
1177      * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1178      *
1179      * <p>Note: if the absolute value of the <code>year</code> parameter
1180      * is less than 10^9, the eon component of the XSD year field is set to
1181      * <code>null</code> by this method.</p>
1182      *
1183      * @param year value constraints are summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1184      *   If year is {@link DatatypeConstants#FIELD_UNDEFINED}, then eon is set to <code>null</code>.
1185      */
1186     public void setYear(int year) {
1187         if (year == DatatypeConstants.FIELD_UNDEFINED) {
1188             this.year = DatatypeConstants.FIELD_UNDEFINED;
1189             this.eon = null;
1190         } else if (Math.abs(year) < BILLION.intValue()) {

1191             this.year = year;
1192             this.eon = null;
1193         } else {
1194             BigInteger theYear = BigInteger.valueOf((long) year);
1195             BigInteger remainder = theYear.remainder(BILLION);
1196             this.year = remainder.intValue();
1197             setEon(theYear.subtract(remainder));
1198         }
1199     }
1200 
1201     /**
1202      * <p>Set high order part of XSD <code>dateTime</code> year field.</p>
1203      *
1204      * <p>Unset this field by invoking the setter with a parameter value of
1205      * <code>null</code>.</p>
1206      *
1207      * @param eon value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1208      */
1209     private void setEon(BigInteger eon) {
1210         if (eon != null && eon.compareTo(BigInteger.ZERO) == 0) {
1211             // Treat ZERO as field being undefined.
1212             this.eon = null;
1213         } else {
1214             this.eon = eon;
1215         }


1671 
1672         if (Qfield == null) {
1673             Qfield = DECIMAL_ZERO;
1674         }
1675 
1676         return Pfield.compareTo(Qfield);
1677     }
1678 
1679     /**
1680      * <p>Indicates whether parameter <code>obj</code> is "equal to" this one.</p>
1681      *
1682      * @param obj to compare.
1683      *
1684      * @return <code>true</code> when <code>compare(this,(XMLGregorianCalendar)obj) == EQUAL.</code>.
1685      */
1686     public boolean equals(Object obj) {
1687 
1688         if (obj == null || !(obj instanceof XMLGregorianCalendar)) {
1689             return false;
1690         }



1691         return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
1692     }
1693 
1694     /**
1695      * <p>Returns a hash code consistent with the definition of the equals method.</p>
1696      *
1697      * @return hash code of this object.
1698      */
1699     public int hashCode() {
1700 
1701         // Following two dates compare to EQUALS since in different timezones.
1702         // 2000-01-15T12:00:00-05:00 == 2000-01-15T13:00:00-04:00
1703         //
1704         // Must ensure both instances generate same hashcode by normalizing
1705         // this to UTC timezone.
1706         int timezone = getTimezone();
1707         if (timezone == DatatypeConstants.FIELD_UNDEFINED) {
1708             timezone = 0;
1709         }
1710         XMLGregorianCalendar gc = this;


1933         default:
1934             throw new IllegalStateException(
1935                 this.getClass().getName()
1936                 + "#getXMLSchemaType() :"
1937                 + DatatypeMessageFormatter.formatMessage(null, "InvalidXGCFields", null)
1938             );
1939         }
1940     }
1941 
1942 
1943     /**
1944      * Validate instance by <code>getXMLSchemaType()</code> constraints.
1945      * @return true if data values are valid.
1946      */
1947     public boolean isValid() {
1948         // since setters do not allow for invalid values,
1949         // (except for exceptional case of year field of zero),
1950         // no need to check for anything except for constraints
1951         // between fields.
1952 
1953         //check if days in month is valid. Can be dependent on leap year.
1954         if (getMonth() == DatatypeConstants.FEBRUARY) {
1955             // years could not be set
1956             int maxDays = 29;
1957 
1958             if (eon == null) {
1959                 if(year!=DatatypeConstants.FIELD_UNDEFINED)
1960                     maxDays = maximumDayInMonthFor(year,getMonth());
1961             } else {
1962                 BigInteger years = getEonAndYear();
1963                 if (years != null) {
1964                     maxDays = maximumDayInMonthFor(getEonAndYear(), DatatypeConstants.FEBRUARY);
1965                 }
1966             }
1967             if (getDay() > maxDays) {
1968                 return false;
1969             }
1970         }





1971 
1972         // http://www.w3.org/2001/05/xmlschema-errata#e2-45
1973         if (getHour() == 24) {
1974             if(getMinute() != 0) {
1975                 return false;
1976             } else if (getSecond() != 0) {
1977                 return false;
1978             }
1979         }
1980 
1981         // XML Schema 1.0 specification defines year value of zero as
1982         // invalid. Allow this class to set year field to zero
1983         // since XML Schema 1.0 errata states that lexical zero will
1984         // be allowed in next version and treated as 1 B.C.E.
1985         if (eon == null) {
1986             // optimize check.
1987             if (year == 0) {
1988                 return false;
1989             }
1990         } else {
1991             BigInteger yearField = getEonAndYear();
1992             if (yearField != null) {
1993                 int result = compareField(yearField, BigInteger.ZERO);
1994                 if (result == DatatypeConstants.EQUAL) {
1995                     return false;
1996                 }
1997             }
1998         }
1999         return true;
2000     }
2001 
2002     /**
2003      * <p>Add <code>duration</code> to this instance.<\p>
2004      *
2005      * <p>The computation is specified in
2006      * <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">XML Schema 1.0 Part 2, Appendix E,
2007      * <i>Adding durations to dateTimes</i>></a>.
2008      * <a href="#datetimefieldsmapping">date/time field mapping table</a>
2009      * defines the mapping from XML Schema 1.0 <code>dateTime</code> fields
2010      * to this class' representation of those fields.</p>
2011      *
2012      * @param duration Duration to add to this <code>XMLGregorianCalendar</code>.
2013      *
2014      * @throws NullPointerException  when <code>duration</code> parameter is <code>null</code>.
2015      */
2016     public void add(Duration duration) {
2017 
2018         /*


2196                 if (month >= 2) {
2197                     mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth() - 1));
2198                 } else {
2199                     // roll over to December of previous year
2200                     mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear().subtract(BigInteger.valueOf((long) 1)), 12));
2201                 }
2202                 endDays = endDays.add(mdimf);
2203                 monthCarry = -1;
2204             } else if (endDays.compareTo(BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth()))) > 0) {
2205                 endDays = endDays.add(BigInteger.valueOf(-maximumDayInMonthFor(getEonAndYear(), getMonth())));
2206                 monthCarry = 1;
2207             } else {
2208                 break;
2209             }
2210 
2211             intTemp = getMonth() + monthCarry;
2212             int endMonth = (intTemp - 1) % (13 - 1);
2213             int quotient;
2214             if (endMonth < 0) {
2215                 endMonth = (13 - 1) + endMonth + 1;
2216                 quotient = new BigDecimal(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
2217             } else {
2218                 quotient = (intTemp - 1) / (13 - 1);
2219                 endMonth += 1;
2220             }
2221             setMonth(endMonth);
2222             if (quotient != 0) {
2223                 setYear(getEonAndYear().add(BigInteger.valueOf(quotient)));
2224             }
2225         }
2226         setDay(endDays.intValue());
2227 
2228         // set fields that where undefined before this addition, back to undefined.
2229         for (int i = YEAR; i <= SECOND; i++) {
2230             if (fieldUndefined[i]) {
2231                 switch (i) {
2232                 case YEAR:
2233                     setYear(DatatypeConstants.FIELD_UNDEFINED);
2234                     break;
2235                 case MONTH:
2236                     setMonth(DatatypeConstants.FIELD_UNDEFINED);


2242                     setHour(DatatypeConstants.FIELD_UNDEFINED, false);
2243                     break;
2244                 case MINUTE:
2245                     setMinute(DatatypeConstants.FIELD_UNDEFINED);
2246                     break;
2247                 case SECOND:
2248                     setSecond(DatatypeConstants.FIELD_UNDEFINED);
2249                     setFractionalSecond(null);
2250                     break;
2251                 }
2252             }
2253         }
2254     }
2255 
2256     private static final BigInteger FOUR = BigInteger.valueOf(4);
2257     private static final BigInteger HUNDRED = BigInteger.valueOf(100);
2258     private static final BigInteger FOUR_HUNDRED = BigInteger.valueOf(400);
2259     private static final BigInteger SIXTY = BigInteger.valueOf(60);
2260     private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24);
2261     private static final BigInteger TWELVE = BigInteger.valueOf(12);
2262     private static final BigDecimal DECIMAL_ZERO = new BigDecimal("0");
2263     private static final BigDecimal DECIMAL_ONE = new BigDecimal("1");
2264     private static final BigDecimal DECIMAL_SIXTY = new BigDecimal("60");
2265 
2266 
2267     private static int daysInMonth[] = { 0,  // XML Schema months start at 1.

2268                                        31, 28, 31, 30, 31, 30,
2269                                        31, 31, 30, 31, 30, 31};

2270 
2271     private static int maximumDayInMonthFor(BigInteger year, int month) {
2272         if (month != DatatypeConstants.FEBRUARY) {
2273             return daysInMonth[month];
2274         } else {
2275             if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) ||
2276                     (!year.mod(HUNDRED).equals(BigInteger.ZERO) &&
2277                             year.mod(FOUR).equals(BigInteger.ZERO))) {
2278                 // is a leap year.
2279                 return 29;
2280             } else {
2281                 return daysInMonth[month];
2282             }
2283         }
2284     }
2285 
2286     private static int maximumDayInMonthFor(int year, int month) {
2287         if (month != DatatypeConstants.FEBRUARY) {
2288             return daysInMonth[month];
2289         } else {
2290             if (((year % 400) == 0) ||
2291                     (((year % 100) != 0) && ((year % 4) == 0))) {
2292                 // is a leap year.
2293                 return 29;
2294             } else {
2295                 return daysInMonth[DatatypeConstants.FEBRUARY];
2296             }
2297         }
2298     }
2299 
2300     /**
2301      * <p>Convert <code>this</code> to <code>java.util.GregorianCalendar</code>.</p>
2302      *
2303      * <p>When <code>this</code> instance has an undefined field, this
2304      * conversion relies on the <code>java.util.GregorianCalendar</code> default
2305      * for its corresponding field. A notable difference between
2306      * XML Schema 1.0 date/time datatypes and <code>java.util.GregorianCalendar</code>
2307      * is that Timezone value is optional for date/time datatypes and it is
2308      * a required field for <code>java.util.GregorianCalendar</code>. See javadoc
2309      * for <code>java.util.TimeZone.getDefault()</code> on how the default
2310      * is determined. To explicitly specify the <code>TimeZone</code>
2311      * instance, see
2312      * {@link #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)}.</p>
2313      *
2314      * <table border="2" rules="all" cellpadding="2">
2315      *   <thead>


2387      * </ul>
2388      * </p>
2389      *
2390      * @see #toGregorianCalendar(java.util.TimeZone, java.util.Locale, XMLGregorianCalendar)
2391      */
2392     public java.util.GregorianCalendar toGregorianCalendar() {
2393 
2394         GregorianCalendar result = null;
2395         final int DEFAULT_TIMEZONE_OFFSET = DatatypeConstants.FIELD_UNDEFINED;
2396         TimeZone tz = getTimeZone(DEFAULT_TIMEZONE_OFFSET);
2397         /** Use the following instead for JDK7 only:
2398          * Locale locale = Locale.getDefault(Locale.Category.FORMAT);
2399          */
2400         Locale locale = getDefaultLocale();
2401 
2402         result = new GregorianCalendar(tz, locale);
2403         result.clear();
2404         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2405 
2406         // if year( and eon) are undefined, leave default Calendar values
2407         BigInteger year = getEonAndYear();
2408         if (year != null) {
2409             result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2410             result.set(Calendar.YEAR, year.abs().intValue());
2411         }






2412 
2413         // only set month if it is set
2414         if (month != DatatypeConstants.FIELD_UNDEFINED) {
2415             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2416             result.set(Calendar.MONTH, month - 1);
2417         }
2418 
2419         // only set day if it is set
2420         if (day != DatatypeConstants.FIELD_UNDEFINED) {
2421             result.set(Calendar.DAY_OF_MONTH, day);
2422         }
2423 
2424         // only set hour if it is set
2425         if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2426             result.set(Calendar.HOUR_OF_DAY, hour);
2427         }
2428 
2429         // only set minute if it is set
2430         if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2431             result.set(Calendar.MINUTE, minute);


2526     public GregorianCalendar toGregorianCalendar(TimeZone timezone,
2527                                                  Locale aLocale,
2528                                                  XMLGregorianCalendar defaults) {
2529         GregorianCalendar result = null;
2530         TimeZone tz = timezone;
2531         if (tz == null) {
2532             int defaultZoneoffset = DatatypeConstants.FIELD_UNDEFINED;
2533             if (defaults != null) {
2534                 defaultZoneoffset = defaults.getTimezone();
2535             }
2536             tz = getTimeZone(defaultZoneoffset);
2537         }
2538         if (aLocale == null) {
2539             aLocale = Locale.getDefault();
2540         }
2541         result = new GregorianCalendar(tz, aLocale);
2542         result.clear();
2543         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2544 
2545         // if year( and eon) are undefined, leave default Calendar values
2546         BigInteger year = getEonAndYear();
2547         if (year != null) {
2548             result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2549             result.set(Calendar.YEAR, year.abs().intValue());






2550         } else {
2551             // use default if set
2552             BigInteger defaultYear = (defaults != null) ? defaults.getEonAndYear() : null;
2553             if (defaultYear != null) {
2554                 result.set(Calendar.ERA, defaultYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2555                 result.set(Calendar.YEAR, defaultYear.abs().intValue());


2556             }




2557         }



2558 
2559         // only set month if it is set
2560         if (month != DatatypeConstants.FIELD_UNDEFINED) {
2561             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2562             result.set(Calendar.MONTH, month - 1);
2563         } else {
2564             // use default if set
2565             int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
2566             if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) {
2567                 // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2568                 result.set(Calendar.MONTH, defaultMonth - 1);
2569             }
2570         }
2571 
2572         // only set day if it is set
2573         if (day != DatatypeConstants.FIELD_UNDEFINED) {
2574             result.set(Calendar.DAY_OF_MONTH, day);
2575         } else {
2576             // use default if set
2577             int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
2578             if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) {
2579                 result.set(Calendar.DAY_OF_MONTH, defaultDay);
2580             }
2581         }
2582 
2583         // only set hour if it is set
2584         if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2585             result.set(Calendar.HOUR_OF_DAY, hour);
2586         } else {
2587             // use default if set
2588             int defaultHour = (defaults != null) ? defaults.getHour() : DatatypeConstants.FIELD_UNDEFINED;
2589             if (defaultHour != DatatypeConstants.FIELD_UNDEFINED) {
2590                 result.set(Calendar.HOUR_OF_DAY, defaultHour);
2591             }
2592         }
2593 
2594         // only set minute if it is set
2595         if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2596             result.set(Calendar.MINUTE, minute);
2597         } else {
2598             // use default if set
2599             int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
2600             if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) {
2601                 result.set(Calendar.MINUTE, defaultMinute);
2602             }
2603         }
2604 
2605         // only set second if it is set
2606         if (second != DatatypeConstants.FIELD_UNDEFINED) {
2607             result.set(Calendar.SECOND, second);
2608         } else {
2609             // use default if set
2610             int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
2611             if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) {
2612                 result.set(Calendar.SECOND, defaultSecond);
2613             }
2614         }
2615 
2616         // only set millisend if it is set
2617         if (fractionalSecond != null) {
2618             result.set(Calendar.MILLISECOND, getMillisecond());
2619         } else {
2620             // use default if set
2621             BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
2622             if (defaultFractionalSecond != null) {
2623                 result.set(Calendar.MILLISECOND, defaults.getMillisecond());
2624             }
2625         }
2626 
2627         return result;
2628     }
2629 
2630     /**
2631      * <p>Returns a <code>java.util.TimeZone</code> for this class.</p>
2632      *
2633      * <p>If timezone field is defined for this instance,
2634      * returns TimeZone initialized with custom timezone id
2635      * of zoneoffset. If timezone field is undefined,
2636      * try the defaultZoneoffset that was passed in.
2637      * If defaultZoneoffset is DatatypeConstants.FIELD_UNDEFINED, return
2638      * default timezone for this host.
2639      * (Same default as java.util.GregorianCalendar).</p>
2640      *
2641      * @param defaultZoneoffset default zoneoffset if this zoneoffset is


2654             result = TimeZone.getDefault();
2655         } else {
2656             // zoneoffset is in minutes. Convert to custom timezone id format.
2657             char sign = zoneoffset < 0 ? '-' : '+';
2658             if (sign == '-') {
2659                 zoneoffset = -zoneoffset;
2660             }
2661             int hour = zoneoffset / 60;
2662             int minutes = zoneoffset - (hour * 60);
2663 
2664             // Javadoc for java.util.TimeZone documents max length
2665             // for customTimezoneId is 8 when optional ':' is not used.
2666             // Format is
2667             // "GMT" ('-'|''+') (digit digit?) (digit digit)?
2668             //                   hour          minutes
2669             StringBuffer customTimezoneId = new StringBuffer(8);
2670             customTimezoneId.append("GMT");
2671             customTimezoneId.append(sign);
2672             customTimezoneId.append(hour);
2673             if (minutes != 0) {



2674                 customTimezoneId.append(minutes);
2675             }
2676             result = TimeZone.getTimeZone(customTimezoneId.toString());
2677         }
2678         return result;
2679     }
2680 
2681     /**
2682      * <p>Creates and returns a copy of this object.</p>
2683      *
2684      * @return copy of this <code>Object</code>
2685      */
2686    public Object clone() {
2687         // Both this.eon and this.fractionalSecond are instances
2688         // of immutable classes, so they do not need to be cloned.
2689        return new XMLGregorianCalendarImpl(getEonAndYear(),
2690                         this.month, this.day,
2691                         this.hour, this.minute, this.second,
2692                         this.fractionalSecond,
2693                         this.timezone);


2701      */
2702     public void clear() {
2703         eon = null;
2704         year = DatatypeConstants.FIELD_UNDEFINED;
2705         month = DatatypeConstants.FIELD_UNDEFINED;
2706         day = DatatypeConstants.FIELD_UNDEFINED;
2707         timezone = DatatypeConstants.FIELD_UNDEFINED;  // in minutes
2708         hour = DatatypeConstants.FIELD_UNDEFINED;
2709         minute = DatatypeConstants.FIELD_UNDEFINED;
2710         second = DatatypeConstants.FIELD_UNDEFINED;
2711         fractionalSecond = null;
2712     }
2713 
2714     public void setMillisecond(int millisecond) {
2715         if (millisecond == DatatypeConstants.FIELD_UNDEFINED) {
2716             fractionalSecond = null;
2717         } else {
2718             if(millisecond<0 || 999<millisecond)
2719                 if(millisecond!=DatatypeConstants.FIELD_UNDEFINED)
2720                     invalidFieldValue(MILLISECOND, millisecond);
2721             fractionalSecond = new BigDecimal((long) millisecond).movePointLeft(3);
2722         }
2723     }
2724 
2725     public void setFractionalSecond(BigDecimal fractional) {
2726         if (fractional != null) {
2727             if ((fractional.compareTo(DECIMAL_ZERO) < 0) ||
2728                     (fractional.compareTo(DECIMAL_ONE) > 0)) {
2729                 throw new IllegalArgumentException(DatatypeMessageFormatter.formatMessage(null,
2730                         "InvalidFractional", new Object[]{fractional}));
2731             }
2732         }
2733         this.fractionalSecond = fractional;
2734     }
2735 
2736     private final class Parser {
2737         private final String format;
2738         private final String value;
2739 
2740         private final int flen;
2741         private final int vlen;


2753         /**
2754          * <p>Parse a formated <code>String</code> into an <code>XMLGregorianCalendar</code>.</p>
2755          *
2756          * <p>If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value,
2757          * an <code>IllegalArgumentException</code> is thrown.</p>
2758          *
2759          * @throws IllegalArgumentException If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value.
2760          */
2761         public void parse() throws IllegalArgumentException {
2762             while (fidx < flen) {
2763                 char fch = format.charAt(fidx++);
2764 
2765                 if (fch != '%') { // not a meta character
2766                     skip(fch);
2767                     continue;
2768                 }
2769 
2770                 // seen meta character. we don't do error check against the format
2771                 switch (format.charAt(fidx++)) {
2772                     case 'Y' : // year
2773                         parseAndSetYear(4);
2774                         break;
2775 
2776                     case 'M' : // month
2777                         setMonth(parseInt(2, 2));
2778                         break;
2779 
2780                     case 'D' : // days
2781                         setDay(parseInt(2, 2));
2782                         break;
2783 
2784                     case 'h' : // hours
2785                         setHour(parseInt(2, 2), false);
2786                         break;
2787 
2788                     case 'm' : // minutes
2789                         setMinute(parseInt(2, 2));
2790                         break;
2791 
2792                     case 's' : // parse seconds.
2793                         setSecond(parseInt(2, 2));


2834 
2835         private char read() throws IllegalArgumentException {
2836             if (vidx == vlen) {
2837                 throw new IllegalArgumentException(value); //,vidx);
2838             }
2839             return value.charAt(vidx++);
2840         }
2841 
2842         private void skip(char ch) throws IllegalArgumentException {
2843             if (read() != ch) {
2844                 throw new IllegalArgumentException(value); //,vidx-1);
2845             }
2846         }
2847 
2848         private int parseInt(int minDigits, int maxDigits)
2849             throws IllegalArgumentException {
2850 
2851             int n = 0;
2852             char ch;
2853             int vstart = vidx;
2854             while (isDigit(ch=peek()) && (vidx - vstart) <= maxDigits) {
2855                 vidx++;
2856                 n = n*10 + ch-'0';
2857             }
2858             if ((vidx - vstart) < minDigits) {
2859                 // we are expecting more digits
2860                 throw new IllegalArgumentException(value); //,vidx);
2861             }
2862 
2863             return n;
2864         }
2865 
2866         private void parseAndSetYear(int minDigits)
2867                 throws IllegalArgumentException {
2868             int vstart = vidx;
2869             int n = 0;
2870             boolean neg = false;
2871 
2872             // skip leading negative, if it exists
2873             if (peek() == '-') {
2874                 vidx++;
2875                 neg = true;
2876             }
2877             while(true) {
2878                 char ch = peek();
2879                 if(!isDigit(ch))
2880                     break;
2881                 vidx++;
2882                 n = n*10 + ch-'0';
2883             }
2884 
2885             if ((vidx - vstart) < minDigits) {
2886                 // we are expecting more digits
2887                 throw new IllegalArgumentException(value); //,vidx);
2888             }
2889 
2890             if(vidx-vstart<7) {
2891                 // definitely int only. I don't know the exact # of digits that can be in int,
2892                 // but as long as we can catch (0-9999) range, that should be enough.
2893                 if(neg)     n = -n;
2894                 year = n;
2895                 eon = null;
2896             } else {
2897                 setYear(new BigInteger(value.substring(vstart, vidx)));
2898             }


2899         }

2900 
2901         private BigDecimal parseBigDecimal()
2902                 throws IllegalArgumentException {
2903             int vstart = vidx;
2904 
2905             if (peek() == '.') {
2906                 vidx++;
2907             } else {
2908                 throw new IllegalArgumentException(value);
2909             }
2910             while (isDigit(peek())) {
2911                 vidx++;
2912             }
2913             return new BigDecimal(value.substring(vstart, vidx));
2914         }
2915     }
2916 
2917     private static boolean isDigit(char ch) {
2918         return '0' <= ch && ch <= '9';
2919     }
2920 
2921     /**
2922      * Prints this object according to the format specification.
2923      *
2924      * <p>
2925      * I wrote a custom format method for a particular format string to
2926      * see if it improves the performance, but it didn't. So this interpreting
2927      * approach isn't too bad.
2928      *
2929      * <p>
2930      * StringBuffer -> StringBuilder change had a very visible impact.
2931      * It almost cut the execution time to half, but unfortunately we can't use it
2932      * because we need to run on JDK 1.3


2933      */
2934     private String format( String format ) {
2935         char[] buf = new char[32];
2936         int bufPtr = 0;
2937 
2938         int fidx=0,flen=format.length();
2939 
2940         while(fidx<flen) {
2941             char fch = format.charAt(fidx++);
2942             if(fch!='%') {// not a meta char
2943                 buf[bufPtr++] = fch;
2944                 continue;
2945             }
2946 
2947             switch(format.charAt(fidx++)) {
2948             case 'Y':
2949                 if(eon==null) {
2950                     // optimized path
2951                     int y = getYear();
2952                     if(y<0) {
2953                         buf[bufPtr++] = '-';
2954                         y = -y;
2955                     }
2956                     bufPtr = print4Number(buf,bufPtr,y);
2957                 } else {
2958                     String s = getEonAndYear().toString();
2959                     // reallocate the buffer now so that it has enough space
2960                     char[] n = new char[buf.length+s.length()];
2961                     System.arraycopy(buf,0,n,0,bufPtr);
2962                     buf = n;
2963                     for(int i=s.length();i<4;i++)
2964                         buf[bufPtr++] = '0';
2965                     s.getChars(0,s.length(),buf,bufPtr);
2966                     bufPtr += s.length();
2967                 }



2968                 break;
2969             case 'M':
2970                 bufPtr = print2Number(buf,bufPtr,getMonth());
2971                 break;
2972             case 'D':
2973                 bufPtr = print2Number(buf,bufPtr,getDay());
2974                 break;
2975             case 'h':
2976                 bufPtr = print2Number(buf,bufPtr,getHour());
2977                 break;
2978             case 'm':
2979                 bufPtr = print2Number(buf,bufPtr,getMinute());
2980                 break;
2981             case 's':
2982                 bufPtr = print2Number(buf,bufPtr,getSecond());
2983                 if (getFractionalSecond() != null) {
2984                     // Note: toPlainString() isn't available before Java 1.5
2985                     String frac = getFractionalSecond().toString();
2986 
2987                     int pos = frac.indexOf("E-");
2988                     if (pos >= 0) {
2989                         String zeros = frac.substring(pos+2);
2990                         frac = frac.substring(0,pos);
2991                         pos = frac.indexOf(".");
2992                         if (pos >= 0) {
2993                             frac = frac.substring(0,pos) + frac.substring(pos+1);
2994                         }
2995                         int count = Integer.parseInt(zeros);
2996                         if (count < 40) {
2997                             frac = "00000000000000000000000000000000000000000".substring(0,count-1) + frac;
2998                         } else {
2999                             // do it the hard way
3000                             while (count > 1) {
3001                                 frac = "0" + frac;
3002                                 count--;
3003                             }
3004                         }
3005                         frac = "0." + frac;
3006                     }
3007 
3008                     // reallocate the buffer now so that it has enough space
3009                     char[] n = new char[buf.length+frac.length()];
3010                     System.arraycopy(buf,0,n,0,bufPtr);
3011                     buf = n;
3012                     //skip leading zero.
3013                     frac.getChars(1, frac.length(), buf, bufPtr);
3014                     bufPtr += frac.length()-1;
3015                 }
3016                 break;
3017             case 'z':
3018                 int offset = getTimezone();
3019                 if (offset == 0) {
3020                     buf[bufPtr++] = 'Z';
3021                 } else
3022                 if (offset != DatatypeConstants.FIELD_UNDEFINED) {
3023                     if (offset < 0) {
3024                         buf[bufPtr++] = '-';
3025                         offset *= -1;
3026                     } else {
3027                         buf[bufPtr++] = '+';
3028                     }
3029                     bufPtr = print2Number(buf, bufPtr, offset / 60);
3030                     buf[bufPtr++] = ':';
3031                     bufPtr = print2Number(buf, bufPtr, offset % 60);
3032                 }




3033                 break;
3034             default:
3035                 throw new InternalError();  // impossible
3036             }
3037         }
3038 
3039         return new String(buf,0,bufPtr);
3040     }
3041 
3042     /**
3043      * Prints an int as two digits into the buffer.
3044      *


3045      * @param number
3046      *      Number to be printed. Must be positive.




3047      */
3048     private int print2Number( char[] out, int bufptr, int number ) {
3049         out[bufptr++] = (char) ('0'+(number/10));
3050         out[bufptr++] = (char) ('0'+(number%10));
3051         return bufptr;
3052     }


3053 
3054     /**
3055      * Prints an int as four digits into the buffer.
3056      *


3057      * @param number
3058      *      Number to be printed. Must be positive.




3059      */
3060     private int print4Number( char[] out, int bufptr, int number ) {
3061         out[bufptr+3] = (char) ('0'+(number%10));
3062         number /= 10;
3063         out[bufptr+2] = (char) ('0'+(number%10));
3064         number /= 10;
3065         out[bufptr+1] = (char) ('0'+(number%10));
3066         number /= 10;
3067         out[bufptr  ] = (char) ('0'+(number%10));
3068         return bufptr+4;
3069     }


3070 
3071     /**
3072      * Compute <code>value*signum</code> where value==null is treated as
3073      * value==0.
3074      * @return non-null {@link BigInteger}.
3075      */
3076     static BigInteger sanitize(Number value, int signum) {
3077         if (signum == 0 || value == null) {
3078             return BigInteger.ZERO;
3079         }
3080         return (signum <  0)? ((BigInteger)value).negate() : (BigInteger)value;
3081     }
3082 
3083     /** <p><code>reset()</code> is designed to allow the reuse of existing
3084      * <code>XMLGregorianCalendar</code>s thus saving resources associated
3085      *  with the creation of new <code>XMLGregorianCalendar</code>s.</p>
3086      */
3087     public void reset() {
3088         //PENDING : Implementation of reset method








3089     }












3090 }


   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.org.apache.xerces.internal.jaxp.datatype;
  27 
  28 import java.io.IOException;
  29 import java.io.ObjectInputStream;
  30 import java.io.Serializable;
  31 import java.math.BigDecimal;
  32 import java.math.BigInteger;
  33 import java.util.TimeZone;
  34 import java.util.Calendar;
  35 import java.util.GregorianCalendar;
  36 import java.util.Date;
  37 import java.util.Locale;
  38 
  39 import javax.xml.datatype.DatatypeConstants;
  40 import javax.xml.datatype.Duration;
  41 import javax.xml.datatype.XMLGregorianCalendar;
  42 import javax.xml.namespace.QName;
  43 import com.sun.org.apache.xerces.internal.util.DatatypeMessageFormatter;
  44 import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
  45 
  46 /**
  47  * <p>Representation for W3C XML Schema 1.0 date/time datatypes.
  48  * Specifically, these date/time datatypes are
  49  * {@link DatatypeConstants#DATETIME dateTime},


 180  *   <li>partial order relation comparator method, {@link #compare(XMLGregorianCalendar)}</li>
 181  *   <li>{@link #equals(Object)} defined relative to {@link #compare(XMLGregorianCalendar)}.</li>
 182  *   <li> addition operation with {@link javax.xml.datatype.Duration}.
 183  * instance as defined in <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">
 184  * W3C XML Schema 1.0 Part 2, Appendix E, <i>Adding durations to dateTimes</i></a>.</li>
 185  * </ul>
 186  * </p>
 187  *
 188  * @author <a href="mailto:Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
 189  * @author <a href="mailto:Joseph.Fialli@Sun.com">Joseph Fialli</a>
 190  * @author <a href="mailto:Sunitha.Reddy@Sun.com">Sunitha Reddy</a>
 191  * @version $Revision: 1.14 $, $Date: 2010-11-10 07:41:41 $
 192  * @see javax.xml.datatype.Duration
 193  * @since 1.5
 194  */
 195 
 196 public class XMLGregorianCalendarImpl
 197         extends XMLGregorianCalendar
 198         implements Serializable, Cloneable {
 199     
 200     /** Backup values **/
 201     transient private BigInteger orig_eon;
 202     transient private int orig_year = DatatypeConstants.FIELD_UNDEFINED;
 203     transient private int orig_month = DatatypeConstants.FIELD_UNDEFINED;
 204     transient private int orig_day = DatatypeConstants.FIELD_UNDEFINED;
 205     transient private int orig_hour = DatatypeConstants.FIELD_UNDEFINED;
 206     transient private int orig_minute = DatatypeConstants.FIELD_UNDEFINED;
 207     transient private int orig_second = DatatypeConstants.FIELD_UNDEFINED;
 208     transient private BigDecimal orig_fracSeconds;
 209     transient private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED;
 210 
 211     /**
 212      * <p>Eon of this <code>XMLGregorianCalendar</code>.</p>
 213      */
 214     private BigInteger eon = null;
 215 
 216     /**
 217      * <p>Year of this <code>XMLGregorianCalendar</code>.</p>
 218      */
 219     private int year = DatatypeConstants.FIELD_UNDEFINED;
 220 
 221     /**
 222      * <p>Month of this <code>XMLGregorianCalendar</code>.</p>
 223      */
 224     private int month = DatatypeConstants.FIELD_UNDEFINED;
 225 
 226     /**
 227      * <p>Day of this <code>XMLGregorianCalendar</code>.</p>
 228      */
 229     private int day = DatatypeConstants.FIELD_UNDEFINED;
 230 


 237      * <p>Hour of this <code>XMLGregorianCalendar</code>.</p>
 238      */
 239     private int hour = DatatypeConstants.FIELD_UNDEFINED;
 240 
 241     /**
 242      * <p>Minute of this <code>XMLGregorianCalendar</code>.</p>
 243      */
 244     private int minute = DatatypeConstants.FIELD_UNDEFINED;
 245 
 246     /**
 247      * <p>Second of this <code>XMLGregorianCalendar</code>.</p>
 248      */
 249     private int second = DatatypeConstants.FIELD_UNDEFINED ;
 250 
 251     /**
 252      * <p>Fractional second of this <code>XMLGregorianCalendar</code>.</p>
 253      */
 254     private BigDecimal fractionalSecond = null;
 255 
 256     /**
 257      * <p>BigInteger constant; representing a billion.</p>
 258      */
 259     private static final BigInteger BILLION_B = new BigInteger("1000000000");
 260     
 261     /**
 262      * <p>int constant; representing a billion.</p>
 263      */
 264     private static final int BILLION_I = 1000000000;
 265     
 266     /**
 267      *   <p>Obtain a pure Gregorian Calendar by calling
 268      *   GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE). </p>
 269      */
 270     private static final Date PURE_GREGORIAN_CHANGE =
 271         new Date(Long.MIN_VALUE);
 272 
 273     /**
 274      * Year index for MIN_ and MAX_FIELD_VALUES.
 275      */
 276     private static final int YEAR   = 0;
 277 
 278     /**
 279      * Month index for MIN_ and MAX_FIELD_VALUES.
 280      */
 281     private static final int MONTH  = 1;
 282 
 283     /**
 284      * Day index for MIN_ and MAX_FIELD_VALUES.
 285      */
 286     private static final int DAY    = 2;


 442                 format = "%Y" + "%z";
 443             } else if (countSeparator == 1) {
 444                 // GYearMonth
 445                 format = "%Y-%M" + "%z";
 446             } else {
 447                 // Date or invalid lexicalRepresentation
 448                 // Fix 4971612: invalid SCCS macro substitution in data string
 449                 format = "%Y-%M-%D" + "%z";
 450             }
 451         }
 452         Parser p = new Parser(format, lexRep);
 453         p.parse();
 454 
 455         // check for validity
 456         if (!isValid()) {
 457             throw new IllegalArgumentException(
 458                     DatatypeMessageFormatter.formatMessage(null, "InvalidXGCRepresentation", new Object[]{lexicalRepresentation})
 459                     //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value."
 460             );
 461         }
 462         
 463         save();
 464     }
 465 
 466     /**
 467      * save original values
 468      */
 469     private void save() {
 470         orig_eon = eon;
 471         orig_year = year;
 472         orig_month = month;
 473         orig_day = day;
 474         orig_hour = hour;
 475         orig_minute = minute;
 476         orig_second = second;
 477         orig_fracSeconds = fractionalSecond;
 478         orig_timezone = timezone;
 479     }
 480     
 481     /**
 482      * <p>Create an instance with all date/time datatype fields set to
 483      * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.</p>
 484      */
 485     public XMLGregorianCalendarImpl() {
 486 
 487         // field initializers already do the correct initialization.
 488     }
 489 
 490     /**
 491      * <p>Private constructor allowing for complete value spaces allowed by
 492      * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
 493      * builtin datatypes. Note that <code>year</code> parameter supports
 494      * arbitrarily large numbers and fractionalSecond has infinite
 495      * precision.</p>
 496      *
 497      * @param year of <code>XMLGregorianCalendar</code> to be created.
 498      * @param month of <code>XMLGregorianCalendar</code> to be created.
 499      * @param day of <code>XMLGregorianCalendar</code> to be created.
 500      * @param hour of <code>XMLGregorianCalendar</code> to be created.
 501      * @param minute of <code>XMLGregorianCalendar</code> to be created.


 539                 String fractionalSecondString = "null";
 540                 if (fractionalSecond != null) {
 541                     fractionalSecondString = fractionalSecond.toString();
 542                 }
 543 
 544                 throw new IllegalArgumentException(
 545                     "year = " + yearString
 546                     + ", month = " + month
 547                     + ", day = " + day
 548                     + ", hour = " + hour
 549                     + ", minute = " + minute
 550                     + ", second = " + second
 551                     + ", fractionalSecond = " + fractionalSecondString
 552                     + ", timezone = " + timezone
 553                     + ", is not a valid representation of an XML Gregorian Calendar value."
 554                 );
 555                 */
 556 
 557         }
 558         
 559         save();
 560     }
 561 
 562     /**
 563      * <p>Private constructor of value spaces that a
 564      * <code>java.util.GregorianCalendar</code> instance would need to convert to an
 565      * <code>XMLGregorianCalendar</code> instance.</p>
 566      *
 567      * <p><code>XMLGregorianCalendar eon</code> and
 568      * <code>fractionalSecond</code> are set to <code>null</code></p>
 569      *
 570      * @param year of <code>XMLGregorianCalendar</code> to be created.
 571      * @param month of <code>XMLGregorianCalendar</code> to be created.
 572      * @param day of <code>XMLGregorianCalendar</code> to be created.
 573      * @param hour of <code>XMLGregorianCalendar</code> to be created.
 574      * @param minute of <code>XMLGregorianCalendar</code> to be created.
 575      * @param second of <code>XMLGregorianCalendar</code> to be created.
 576      * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
 577      * @param timezone of <code>XMLGregorianCalendar</code> to be created.
 578      */
 579     private XMLGregorianCalendarImpl(
 580         int year,
 581         int month,
 582         int day,
 583         int hour,
 584         int minute,
 585         int second,
 586         int millisecond,
 587         int timezone) {
 588 
 589         setYear(year);
 590         setMonth(month);
 591         setDay(day);
 592         setTime(hour, minute, second);
 593         setTimezone(timezone);
 594         BigDecimal realMilliseconds = null;
 595         if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
 596             realMilliseconds = BigDecimal.valueOf(millisecond, 3);
 597         }
 598         setFractionalSecond(realMilliseconds);
 599 
 600         if (!isValid()) {
 601 
 602             throw new IllegalArgumentException(
 603                 DatatypeMessageFormatter.formatMessage(null,
 604                 "InvalidXGCValue-milli",
 605                 new Object[] { new Integer(year), new Integer(month), new Integer(day),
 606                 new Integer(hour), new Integer(minute), new Integer(second),
 607                 new Integer(millisecond), new Integer(timezone)})
 608                         );
 609                 /*
 610                 throw new IllegalArgumentException(
 611                     "year = " + year
 612                     + ", month = " + month
 613                     + ", day = " + day
 614                     + ", hour = " + hour
 615                     + ", minute = " + minute
 616                     + ", second = " + second
 617                     + ", millisecond = " + millisecond
 618                     + ", timezone = " + timezone
 619                     + ", is not a valid representation of an XML Gregorian Calendar value."
 620                     );
 621                  */
 622 
 623         }
 624         
 625         save();
 626     }
 627 
 628         /**
 629          * <p>Convert a <code>java.util.GregorianCalendar</code> to XML Schema 1.0
 630          * representation.</p>
 631          *
 632          * <table border="2" rules="all" cellpadding="2">
 633          *   <thead>
 634          *     <tr>
 635          *       <th align="center" colspan="2">
 636          *          Field by Field Conversion from
 637          *          <code>java.util.GregorianCalendar</code> to this class
 638          *       </th>
 639          *     </tr>
 640          *   </thead>
 641          *   <tbody>
 642          *     <tr>
 643          *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
 644          *        <th><code>java.util.GregorianCalendar</code> field</th>
 645          *     </tr>


 686 
 687         int year = cal.get(Calendar.YEAR);
 688         if (cal.get(Calendar.ERA) == GregorianCalendar.BC) {
 689             year = -year;
 690         }
 691         this.setYear(year);
 692 
 693         // Calendar.MONTH is zero based, XSD Date datatype's month field starts
 694         // with JANUARY as 1.
 695         this.setMonth(cal.get(Calendar.MONTH) + 1);
 696         this.setDay(cal.get(Calendar.DAY_OF_MONTH));
 697         this.setTime(
 698                 cal.get(Calendar.HOUR_OF_DAY),
 699                 cal.get(Calendar.MINUTE),
 700                 cal.get(Calendar.SECOND),
 701                 cal.get(Calendar.MILLISECOND));
 702 
 703         // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds.
 704         int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
 705         this.setTimezone(offsetInMinutes);
 706         save();
 707     }
 708 
 709     // Factories
 710 
 711     /**
 712      * <p>Create a Java representation of XML Schema builtin datatype <code>dateTime</code>.
 713      * All possible fields are specified for this factory method.</p>
 714      *
 715      * @param year represents both high-order eons and low-order year.
 716      * @param month of <code>dateTime</code>
 717      * @param day of <code>dateTime</code>
 718      * @param hours of <code>dateTime</code>
 719      * @param minutes of <code>dateTime</code>
 720      * @param seconds of <code>dateTime</code>
 721      * @param fractionalSecond value of null indicates optional field is absent.
 722      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 723      *
 724      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 725      *
 726      * @see DatatypeConstants#FIELD_UNDEFINED


1190     }
1191 
1192     // setters
1193 
1194     /**
1195      * <p>Set low and high order component of XSD <code>dateTime</code> year field.</p>
1196      *
1197      * <p>Unset this field by invoking the setter with a parameter value of <code>null</code>.</p>
1198      *
1199      * @param year value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1200      *
1201      * @throws IllegalArgumentException if <code>year</code> parameter is
1202      * outside value constraints for the field as specified in
1203      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1204      */
1205     public void setYear(BigInteger year) {
1206         if (year == null) {
1207             this.eon = null;
1208             this.year = DatatypeConstants.FIELD_UNDEFINED;
1209         } else {
1210             BigInteger temp = year.remainder(BILLION_B);
1211             this.year = temp.intValue();
1212             setEon(year.subtract(temp));
1213         }
1214     }
1215 
1216     /**
1217      * <p>Set year of XSD <code>dateTime</code> year field.</p>
1218      *
1219      * <p>Unset this field by invoking the setter with a parameter value of
1220      * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1221      *
1222      * <p>Note: if the absolute value of the <code>year</code> parameter
1223      * is less than 10^9, the eon component of the XSD year field is set to
1224      * <code>null</code> by this method.</p>
1225      *
1226      * @param year value constraints are summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1227      *   If year is {@link DatatypeConstants#FIELD_UNDEFINED}, then eon is set to <code>null</code>.
1228      */
1229     public void setYear(int year) {
1230         if (year == DatatypeConstants.FIELD_UNDEFINED) {
1231             this.year = DatatypeConstants.FIELD_UNDEFINED;
1232             this.eon = null;
1233         } 
1234         else if (Math.abs(year) < BILLION_I) {
1235             this.year = year;
1236             this.eon = null;
1237         } else {
1238             BigInteger theYear = BigInteger.valueOf((long) year);
1239             BigInteger remainder = theYear.remainder(BILLION_B);
1240             this.year = remainder.intValue();
1241             setEon(theYear.subtract(remainder));
1242         }
1243     }
1244 
1245     /**
1246      * <p>Set high order part of XSD <code>dateTime</code> year field.</p>
1247      *
1248      * <p>Unset this field by invoking the setter with a parameter value of
1249      * <code>null</code>.</p>
1250      *
1251      * @param eon value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1252      */
1253     private void setEon(BigInteger eon) {
1254         if (eon != null && eon.compareTo(BigInteger.ZERO) == 0) {
1255             // Treat ZERO as field being undefined.
1256             this.eon = null;
1257         } else {
1258             this.eon = eon;
1259         }


1715 
1716         if (Qfield == null) {
1717             Qfield = DECIMAL_ZERO;
1718         }
1719 
1720         return Pfield.compareTo(Qfield);
1721     }
1722 
1723     /**
1724      * <p>Indicates whether parameter <code>obj</code> is "equal to" this one.</p>
1725      *
1726      * @param obj to compare.
1727      *
1728      * @return <code>true</code> when <code>compare(this,(XMLGregorianCalendar)obj) == EQUAL.</code>.
1729      */
1730     public boolean equals(Object obj) {
1731         
1732         if (obj == null || !(obj instanceof XMLGregorianCalendar)) {
1733             return false;
1734         }
1735         if (obj == this) {
1736             return true;
1737         }
1738         return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
1739     }
1740 
1741     /**
1742      * <p>Returns a hash code consistent with the definition of the equals method.</p>
1743      *
1744      * @return hash code of this object.
1745      */
1746     public int hashCode() {
1747 
1748         // Following two dates compare to EQUALS since in different timezones.
1749         // 2000-01-15T12:00:00-05:00 == 2000-01-15T13:00:00-04:00
1750         //
1751         // Must ensure both instances generate same hashcode by normalizing
1752         // this to UTC timezone.
1753         int timezone = getTimezone();
1754         if (timezone == DatatypeConstants.FIELD_UNDEFINED) {
1755             timezone = 0;
1756         }
1757         XMLGregorianCalendar gc = this;


1980         default:
1981             throw new IllegalStateException(
1982                 this.getClass().getName()
1983                 + "#getXMLSchemaType() :"
1984                 + DatatypeMessageFormatter.formatMessage(null, "InvalidXGCFields", null)
1985             );
1986         }
1987     }
1988 
1989 
1990     /**
1991      * Validate instance by <code>getXMLSchemaType()</code> constraints.
1992      * @return true if data values are valid.
1993      */
1994     public boolean isValid() {
1995         // since setters do not allow for invalid values, 
1996         // (except for exceptional case of year field of zero),
1997         // no need to check for anything except for constraints
1998         // between fields. 
1999 
2000         // check if days in month is valid. Can be dependent on leap year.
2001         if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) {
2002             if (year != DatatypeConstants.FIELD_UNDEFINED) {


2003                 if (eon == null) {
2004                     if (day > maximumDayInMonthFor(year, month)) {
2005                         return false;




2006                     }
2007                 }
2008                 else if (day > maximumDayInMonthFor(getEonAndYear(), month)) {
2009                     return false;
2010                 }
2011             }
2012             // Use 2000 as a default since it's a leap year.
2013             else if (day > maximumDayInMonthFor(2000, month)) {
2014                 return false;
2015             }
2016         }
2017 
2018         // http://www.w3.org/2001/05/xmlschema-errata#e2-45
2019         if (hour == 24 && (minute != 0 || second != 0 || 
2020                 (fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) {
2021             return false;


2022         }

2023 
2024         // XML Schema 1.0 specification defines year value of zero as
2025         // invalid. Allow this class to set year field to zero
2026         // since XML Schema 1.0 errata states that lexical zero will 
2027         // be allowed in next version and treated as 1 B.C.E.
2028         if (eon == null && year == 0) {


2029             return false;
2030         }









2031         return true;
2032     }
2033 
2034     /**
2035      * <p>Add <code>duration</code> to this instance.<\p>
2036      *
2037      * <p>The computation is specified in
2038      * <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">XML Schema 1.0 Part 2, Appendix E,
2039      * <i>Adding durations to dateTimes</i>></a>.
2040      * <a href="#datetimefieldsmapping">date/time field mapping table</a>
2041      * defines the mapping from XML Schema 1.0 <code>dateTime</code> fields
2042      * to this class' representation of those fields.</p>
2043      *
2044      * @param duration Duration to add to this <code>XMLGregorianCalendar</code>.
2045      *
2046      * @throws NullPointerException  when <code>duration</code> parameter is <code>null</code>.
2047      */
2048     public void add(Duration duration) {
2049 
2050         /*


2228                 if (month >= 2) {
2229                     mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth() - 1));
2230                 } else {
2231                     // roll over to December of previous year
2232                     mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear().subtract(BigInteger.valueOf((long) 1)), 12));
2233                 }
2234                 endDays = endDays.add(mdimf);
2235                 monthCarry = -1;
2236             } else if (endDays.compareTo(BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(), getMonth()))) > 0) {
2237                 endDays = endDays.add(BigInteger.valueOf(-maximumDayInMonthFor(getEonAndYear(), getMonth())));
2238                 monthCarry = 1;
2239             } else {
2240                 break;
2241             }
2242 
2243             intTemp = getMonth() + monthCarry;
2244             int endMonth = (intTemp - 1) % (13 - 1);
2245             int quotient;
2246             if (endMonth < 0) {
2247                 endMonth = (13 - 1) + endMonth + 1;
2248                 quotient = BigDecimal.valueOf(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
2249             } else {
2250                 quotient = (intTemp - 1) / (13 - 1);
2251                 endMonth += 1;
2252             }
2253             setMonth(endMonth);
2254             if (quotient != 0) {
2255                 setYear(getEonAndYear().add(BigInteger.valueOf(quotient)));
2256             }
2257         }
2258         setDay(endDays.intValue());
2259 
2260         // set fields that where undefined before this addition, back to undefined.
2261         for (int i = YEAR; i <= SECOND; i++) {
2262             if (fieldUndefined[i]) {
2263                 switch (i) {
2264                 case YEAR:
2265                     setYear(DatatypeConstants.FIELD_UNDEFINED);
2266                     break;
2267                 case MONTH:
2268                     setMonth(DatatypeConstants.FIELD_UNDEFINED);


2274                     setHour(DatatypeConstants.FIELD_UNDEFINED, false);
2275                     break;
2276                 case MINUTE:
2277                     setMinute(DatatypeConstants.FIELD_UNDEFINED);
2278                     break;
2279                 case SECOND:
2280                     setSecond(DatatypeConstants.FIELD_UNDEFINED);
2281                     setFractionalSecond(null);
2282                     break;
2283                 }
2284             }
2285         }
2286     }
2287 
2288     private static final BigInteger FOUR = BigInteger.valueOf(4);
2289     private static final BigInteger HUNDRED = BigInteger.valueOf(100);
2290     private static final BigInteger FOUR_HUNDRED = BigInteger.valueOf(400);
2291     private static final BigInteger SIXTY = BigInteger.valueOf(60);
2292     private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24);
2293     private static final BigInteger TWELVE = BigInteger.valueOf(12);
2294     private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0);
2295     private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1);
2296     private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60);
2297 
2298 
2299     private static class DaysInMonth {
2300         private static final int [] table = { 0,  // XML Schema months start at 1.
2301             31, 28, 31, 30, 31, 30,
2302             31, 31, 30, 31, 30, 31};
2303     }
2304 
2305     private static int maximumDayInMonthFor(BigInteger year, int month) {
2306         if (month != DatatypeConstants.FEBRUARY) {
2307             return DaysInMonth.table[month];
2308         } else {
2309             if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) ||
2310                     (!year.mod(HUNDRED).equals(BigInteger.ZERO) &&
2311                             year.mod(FOUR).equals(BigInteger.ZERO))) {
2312                 // is a leap year.
2313                 return 29;
2314             } else {
2315                 return DaysInMonth.table[month];
2316             }
2317         }
2318     }
2319 
2320     private static int maximumDayInMonthFor(int year, int month) {
2321         if (month != DatatypeConstants.FEBRUARY) {
2322             return DaysInMonth.table[month];
2323         } else {
2324             if (((year % 400) == 0) ||
2325                     (((year % 100) != 0) && ((year % 4) == 0))) {
2326                 // is a leap year.
2327                 return 29;
2328             } else {
2329                 return DaysInMonth.table[DatatypeConstants.FEBRUARY];
2330             }
2331         }
2332     }
2333 
2334     /**
2335      * <p>Convert <code>this</code> to <code>java.util.GregorianCalendar</code>.</p>
2336      *
2337      * <p>When <code>this</code> instance has an undefined field, this
2338      * conversion relies on the <code>java.util.GregorianCalendar</code> default
2339      * for its corresponding field. A notable difference between
2340      * XML Schema 1.0 date/time datatypes and <code>java.util.GregorianCalendar</code>
2341      * is that Timezone value is optional for date/time datatypes and it is
2342      * a required field for <code>java.util.GregorianCalendar</code>. See javadoc
2343      * for <code>java.util.TimeZone.getDefault()</code> on how the default
2344      * is determined. To explicitly specify the <code>TimeZone</code>
2345      * instance, see
2346      * {@link #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)}.</p>
2347      *
2348      * <table border="2" rules="all" cellpadding="2">
2349      *   <thead>


2421      * </ul>
2422      * </p>
2423      *
2424      * @see #toGregorianCalendar(java.util.TimeZone, java.util.Locale, XMLGregorianCalendar)
2425      */
2426     public java.util.GregorianCalendar toGregorianCalendar() {
2427 
2428         GregorianCalendar result = null;
2429         final int DEFAULT_TIMEZONE_OFFSET = DatatypeConstants.FIELD_UNDEFINED;
2430         TimeZone tz = getTimeZone(DEFAULT_TIMEZONE_OFFSET);
2431         /** Use the following instead for JDK7 only:
2432          * Locale locale = Locale.getDefault(Locale.Category.FORMAT);
2433          */
2434         Locale locale = getDefaultLocale();
2435 
2436         result = new GregorianCalendar(tz, locale);
2437         result.clear();
2438         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2439 
2440         // if year( and eon) are undefined, leave default Calendar values
2441         if (year != DatatypeConstants.FIELD_UNDEFINED) {
2442             if (eon == null) {
2443                 result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2444                 result.set(Calendar.YEAR, Math.abs(year));
2445             }
2446             else {
2447                 BigInteger eonAndYear = getEonAndYear();
2448                 result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2449                 result.set(Calendar.YEAR, eonAndYear.abs().intValue());
2450             }
2451         }
2452 
2453         // only set month if it is set
2454         if (month != DatatypeConstants.FIELD_UNDEFINED) {
2455             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2456             result.set(Calendar.MONTH, month - 1);
2457         }
2458 
2459         // only set day if it is set
2460         if (day != DatatypeConstants.FIELD_UNDEFINED) {
2461             result.set(Calendar.DAY_OF_MONTH, day);
2462         }
2463 
2464         // only set hour if it is set
2465         if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2466             result.set(Calendar.HOUR_OF_DAY, hour);
2467         }
2468 
2469         // only set minute if it is set
2470         if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2471             result.set(Calendar.MINUTE, minute);


2566     public GregorianCalendar toGregorianCalendar(TimeZone timezone,
2567                                                  Locale aLocale,
2568                                                  XMLGregorianCalendar defaults) {
2569         GregorianCalendar result = null;
2570         TimeZone tz = timezone;
2571         if (tz == null) {
2572             int defaultZoneoffset = DatatypeConstants.FIELD_UNDEFINED;
2573             if (defaults != null) {
2574                 defaultZoneoffset = defaults.getTimezone();
2575             }
2576             tz = getTimeZone(defaultZoneoffset);
2577         }
2578         if (aLocale == null) {
2579             aLocale = Locale.getDefault();
2580         }
2581         result = new GregorianCalendar(tz, aLocale);
2582         result.clear();
2583         result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2584 
2585         // if year( and eon) are undefined, leave default Calendar values
2586         if (year != DatatypeConstants.FIELD_UNDEFINED) {
2587             if (eon == null) {
2588                 result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2589                 result.set(Calendar.YEAR, Math.abs(year));
2590             }
2591             else {
2592                 final BigInteger eonAndYear = getEonAndYear();
2593                 result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2594                 result.set(Calendar.YEAR, eonAndYear.abs().intValue());
2595             }
2596         } else {
2597             // use default if set
2598             if (defaults != null) {
2599                 final int defaultYear = defaults.getYear();
2600                 if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) {
2601                     if (defaults.getEon() == null) {
2602                         result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2603                         result.set(Calendar.YEAR, Math.abs(defaultYear));
2604                     }
2605                     else {
2606                         final BigInteger defaultEonAndYear = defaults.getEonAndYear();
2607                         result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2608                         result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue());
2609                     }
2610                 }
2611             }
2612         }
2613 
2614         // only set month if it is set
2615         if (month != DatatypeConstants.FIELD_UNDEFINED) {
2616             // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2617             result.set(Calendar.MONTH, month - 1);
2618         } else {
2619             // use default if set
2620             final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
2621             if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) {
2622                 // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2623                 result.set(Calendar.MONTH, defaultMonth - 1);
2624             }
2625         }
2626 
2627         // only set day if it is set
2628         if (day != DatatypeConstants.FIELD_UNDEFINED) {
2629             result.set(Calendar.DAY_OF_MONTH, day);
2630         } else {
2631             // use default if set
2632             final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
2633             if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) {
2634                 result.set(Calendar.DAY_OF_MONTH, defaultDay);
2635             }
2636         }
2637 
2638         // only set hour if it is set
2639         if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2640             result.set(Calendar.HOUR_OF_DAY, hour);
2641         } else {
2642             // use default if set
2643             int defaultHour = (defaults != null) ? defaults.getHour() : DatatypeConstants.FIELD_UNDEFINED;
2644             if (defaultHour != DatatypeConstants.FIELD_UNDEFINED) {
2645                 result.set(Calendar.HOUR_OF_DAY, defaultHour);
2646             }
2647         }
2648 
2649         // only set minute if it is set
2650         if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2651             result.set(Calendar.MINUTE, minute);
2652         } else {
2653             // use default if set
2654             final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
2655             if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) {
2656                 result.set(Calendar.MINUTE, defaultMinute);
2657             }
2658         }
2659 
2660         // only set second if it is set
2661         if (second != DatatypeConstants.FIELD_UNDEFINED) {
2662             result.set(Calendar.SECOND, second);
2663         } else {
2664             // use default if set
2665             final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
2666             if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) {
2667                 result.set(Calendar.SECOND, defaultSecond);
2668             }
2669         }
2670 
2671         // only set millisend if it is set
2672         if (fractionalSecond != null) {
2673             result.set(Calendar.MILLISECOND, getMillisecond());
2674         } else {
2675             // use default if set
2676             final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
2677             if (defaultFractionalSecond != null) {
2678                 result.set(Calendar.MILLISECOND, defaults.getMillisecond());
2679             }
2680         }
2681 
2682         return result;
2683     }
2684 
2685     /**
2686      * <p>Returns a <code>java.util.TimeZone</code> for this class.</p>
2687      *
2688      * <p>If timezone field is defined for this instance,
2689      * returns TimeZone initialized with custom timezone id
2690      * of zoneoffset. If timezone field is undefined,
2691      * try the defaultZoneoffset that was passed in.
2692      * If defaultZoneoffset is DatatypeConstants.FIELD_UNDEFINED, return
2693      * default timezone for this host.
2694      * (Same default as java.util.GregorianCalendar).</p>
2695      *
2696      * @param defaultZoneoffset default zoneoffset if this zoneoffset is


2709             result = TimeZone.getDefault();
2710         } else {
2711             // zoneoffset is in minutes. Convert to custom timezone id format.
2712             char sign = zoneoffset < 0 ? '-' : '+';
2713             if (sign == '-') {
2714                 zoneoffset = -zoneoffset;
2715             }
2716             int hour = zoneoffset / 60;
2717             int minutes = zoneoffset - (hour * 60);
2718 
2719             // Javadoc for java.util.TimeZone documents max length
2720             // for customTimezoneId is 8 when optional ':' is not used.
2721             // Format is
2722             // "GMT" ('-'|''+') (digit digit?) (digit digit)?
2723             //                   hour          minutes
2724             StringBuffer customTimezoneId = new StringBuffer(8);
2725             customTimezoneId.append("GMT");
2726             customTimezoneId.append(sign);
2727             customTimezoneId.append(hour);
2728             if (minutes != 0) {
2729                 if (minutes < 10) {
2730                     customTimezoneId.append('0');
2731                 }
2732                 customTimezoneId.append(minutes);
2733             }
2734             result = TimeZone.getTimeZone(customTimezoneId.toString());
2735         }
2736         return result;
2737     }
2738 
2739     /**
2740      * <p>Creates and returns a copy of this object.</p>
2741      *
2742      * @return copy of this <code>Object</code>
2743      */
2744    public Object clone() {
2745         // Both this.eon and this.fractionalSecond are instances
2746         // of immutable classes, so they do not need to be cloned.
2747        return new XMLGregorianCalendarImpl(getEonAndYear(),
2748                         this.month, this.day,
2749                         this.hour, this.minute, this.second,
2750                         this.fractionalSecond,
2751                         this.timezone);


2759      */
2760     public void clear() {
2761         eon = null;
2762         year = DatatypeConstants.FIELD_UNDEFINED;
2763         month = DatatypeConstants.FIELD_UNDEFINED;
2764         day = DatatypeConstants.FIELD_UNDEFINED;
2765         timezone = DatatypeConstants.FIELD_UNDEFINED;  // in minutes
2766         hour = DatatypeConstants.FIELD_UNDEFINED;
2767         minute = DatatypeConstants.FIELD_UNDEFINED;
2768         second = DatatypeConstants.FIELD_UNDEFINED;
2769         fractionalSecond = null;
2770     }
2771 
2772     public void setMillisecond(int millisecond) {
2773         if (millisecond == DatatypeConstants.FIELD_UNDEFINED) {
2774             fractionalSecond = null;
2775         } else {
2776             if(millisecond<0 || 999<millisecond)
2777                 if(millisecond!=DatatypeConstants.FIELD_UNDEFINED)
2778                     invalidFieldValue(MILLISECOND, millisecond);
2779             fractionalSecond = BigDecimal.valueOf(millisecond, 3);
2780         }
2781     }
2782 
2783     public void setFractionalSecond(BigDecimal fractional) {
2784         if (fractional != null) {
2785             if ((fractional.compareTo(DECIMAL_ZERO) < 0) ||
2786                     (fractional.compareTo(DECIMAL_ONE) > 0)) {
2787                 throw new IllegalArgumentException(DatatypeMessageFormatter.formatMessage(null,
2788                         "InvalidFractional", new Object[]{fractional}));
2789             }
2790         }
2791         this.fractionalSecond = fractional;
2792     }
2793 
2794     private final class Parser {
2795         private final String format;
2796         private final String value;
2797 
2798         private final int flen;
2799         private final int vlen;


2811         /**
2812          * <p>Parse a formated <code>String</code> into an <code>XMLGregorianCalendar</code>.</p>
2813          *
2814          * <p>If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value,
2815          * an <code>IllegalArgumentException</code> is thrown.</p>
2816          *
2817          * @throws IllegalArgumentException If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value.
2818          */
2819         public void parse() throws IllegalArgumentException {
2820             while (fidx < flen) {
2821                 char fch = format.charAt(fidx++);
2822 
2823                 if (fch != '%') { // not a meta character
2824                     skip(fch);
2825                     continue;
2826                 }
2827 
2828                 // seen meta character. we don't do error check against the format
2829                 switch (format.charAt(fidx++)) {
2830                     case 'Y' : // year
2831                         parseYear();
2832                         break;
2833 
2834                     case 'M' : // month
2835                         setMonth(parseInt(2, 2));
2836                         break;
2837 
2838                     case 'D' : // days
2839                         setDay(parseInt(2, 2));
2840                         break;
2841 
2842                     case 'h' : // hours
2843                         setHour(parseInt(2, 2), false);
2844                         break;
2845 
2846                     case 'm' : // minutes
2847                         setMinute(parseInt(2, 2));
2848                         break;
2849 
2850                     case 's' : // parse seconds.
2851                         setSecond(parseInt(2, 2));


2892 
2893         private char read() throws IllegalArgumentException {
2894             if (vidx == vlen) {
2895                 throw new IllegalArgumentException(value); //,vidx);
2896             }
2897             return value.charAt(vidx++);
2898         }
2899 
2900         private void skip(char ch) throws IllegalArgumentException {
2901             if (read() != ch) {
2902                 throw new IllegalArgumentException(value); //,vidx-1);
2903             }
2904         }
2905 
2906         private int parseInt(int minDigits, int maxDigits)
2907             throws IllegalArgumentException {
2908 
2909             int n = 0;
2910             char ch;
2911             int vstart = vidx;
2912             while (isDigit(ch=peek()) && (vidx - vstart) < maxDigits) {
2913                 vidx++;
2914                 n = n*10 + ch-'0';
2915             }
2916             if ((vidx - vstart) < minDigits) {
2917                 // we are expecting more digits
2918                 throw new IllegalArgumentException(value); //,vidx);
2919             }
2920 
2921             return n;
2922         }
2923 
2924         private void parseYear()
2925             throws IllegalArgumentException {
2926             int vstart = vidx;
2927             int sign = 0;

2928             
2929             // skip leading negative, if it exists
2930             if (peek() == '-') {
2931                 vidx++;
2932                 sign = 1;
2933             }
2934             while (isDigit(peek())) {



2935                 vidx++;

2936             }
2937             final int digits = vidx - vstart - sign;
2938             if (digits < 4) {
2939                 // we are expecting more digits
2940                 throw new IllegalArgumentException(value); //,vidx);
2941             }
2942             final String yearString = value.substring(vstart, vidx);
2943             if (digits < 10) {
2944                 setYear(Integer.parseInt(yearString));






2945             }
2946             else {
2947                 setYear(new BigInteger(yearString));
2948             }
2949         }
2950 
2951         private BigDecimal parseBigDecimal()
2952                 throws IllegalArgumentException {
2953             int vstart = vidx;
2954 
2955             if (peek() == '.') {
2956                 vidx++;
2957             } else {
2958                 throw new IllegalArgumentException(value);
2959             }
2960             while (isDigit(peek())) {
2961                 vidx++;
2962             }
2963             return new BigDecimal(value.substring(vstart, vidx));
2964         }
2965     }
2966 
2967     private static boolean isDigit(char ch) {
2968         return '0' <= ch && ch <= '9';
2969     }
2970 
2971     /**
2972      * Prints this object according to the format specification.
2973      *
2974      * <p>





2975      * StringBuffer -> StringBuilder change had a very visible impact.
2976      * It almost cut the execution time to half.
2977      * Diff from Xerces:
2978      * Xerces use StringBuffer due to the requirement to support
2979      * JDKs older than JDK 1.5
2980      */
2981     private String format( String format ) {
2982         StringBuilder buf = new StringBuilder();


2983         int fidx=0,flen=format.length();
2984 
2985         while(fidx<flen) {
2986             char fch = format.charAt(fidx++);
2987             if(fch!='%') {// not a meta char
2988                 buf.append(fch);
2989                 continue;
2990             }
2991 
2992             switch(format.charAt(fidx++)) {
2993                 case 'Y':
2994                     if (eon == null) {
2995                         int absYear = year;
2996                         if (absYear < 0) {
2997                             buf.append('-');
2998                             absYear = -year;

2999                         }
3000                         printNumber(buf, absYear, 4);










3001                     }
3002                     else {
3003                         printNumber(buf, getEonAndYear(), 4);
3004                     }
3005                     break;
3006                 case 'M':
3007                     printNumber(buf,getMonth(),2);
3008                     break;
3009                 case 'D':
3010                     printNumber(buf,getDay(),2);
3011                     break;
3012                 case 'h':
3013                     printNumber(buf,getHour(),2);
3014                     break;
3015                 case 'm':
3016                     printNumber(buf,getMinute(),2);
3017                     break;
3018                 case 's':
3019                     printNumber(buf,getSecond(),2);
3020                     if (getFractionalSecond() != null) {
3021                         //Xerces uses a custom method toString instead of
3022                         //toPlainString() since it needs to support JDKs older than 1.5
3023                         String frac = getFractionalSecond().toPlainString();

























3024                         //skip leading zero.
3025                         buf.append(frac.substring(1, frac.length()));

3026                     } 
3027                     break;
3028                 case 'z':
3029                     int offset = getTimezone();
3030                     if (offset == 0) {
3031                         buf.append('Z');
3032                     } 
3033                     else if (offset != DatatypeConstants.FIELD_UNDEFINED) {
3034                         if (offset < 0) {
3035                             buf.append('-');
3036                             offset *= -1; 


3037                         } 
3038                         else {
3039                             buf.append('+');

3040                         }
3041                         printNumber(buf,offset/60,2);
3042                         buf.append(':');
3043                         printNumber(buf,offset%60,2);
3044                     }
3045                     break;
3046                 default:
3047                     throw new InternalError();  // impossible
3048             }
3049         }
3050 
3051         return buf.toString();
3052     }
3053 
3054     /**
3055      * Prints an integer as a String. 
3056      * 
3057      * @param out
3058      *      The formatted string will be appended into this buffer.
3059      * @param number
3060      *      The integer to be printed. 
3061      * @param nDigits
3062      *      The field will be printed by using at least this
3063      *      number of digits. For example, 5 will be printed as "0005"
3064      *      if nDigits==4. 
3065      */
3066     private void printNumber( StringBuilder out, int number, int nDigits ) {
3067         String s = String.valueOf(number);
3068         for (int i = s.length(); i < nDigits; i++) {
3069             out.append('0');
3070         }
3071         out.append(s);
3072     }
3073 
3074     /**
3075      * Prints an BigInteger as a String. 
3076      * 
3077      * @param out
3078      *      The formatted string will be appended into this buffer.
3079      * @param number
3080      *      The integer to be printed. 
3081      * @param nDigits
3082      *      The field will be printed by using at least this
3083      *      number of digits. For example, 5 will be printed as "0005"
3084      *      if nDigits==4. 
3085      */
3086     private void printNumber( StringBuilder out, BigInteger number, int nDigits) {
3087         String s = number.toString();
3088         for (int i=s.length(); i < nDigits; i++) {
3089             out.append('0');





3090         }
3091         out.append(s);
3092     }
3093 
3094     /**
3095      * Compute <code>value*signum</code> where value==null is treated as
3096      * value==0.
3097      * @return non-null {@link BigInteger}.
3098      */
3099     static BigInteger sanitize(Number value, int signum) {
3100         if (signum == 0 || value == null) {
3101             return BigInteger.ZERO;
3102         }
3103         return (signum <  0)? ((BigInteger)value).negate() : (BigInteger)value;
3104     }
3105 
3106     /** <p><code>reset()</code> is designed to allow the reuse of existing
3107      * <code>XMLGregorianCalendar</code>s thus saving resources associated
3108      *  with the creation of new <code>XMLGregorianCalendar</code>s.</p>
3109      */
3110     public void reset() {
3111         eon = orig_eon;
3112         year = orig_year;
3113         month = orig_month;
3114         day = orig_day;
3115         hour = orig_hour;
3116         minute = orig_minute;
3117         second = orig_second;
3118         fractionalSecond = orig_fracSeconds;
3119         timezone = orig_timezone;
3120     }
3121 
3122     /** Deserialize Calendar. */
3123     private void readObject(ObjectInputStream ois)
3124         throws ClassNotFoundException, IOException {
3125 
3126         // perform default deseralization
3127         ois.defaultReadObject();
3128 
3129         // initialize orig_* fields
3130         save();
3131 
3132     } // readObject(ObjectInputStream)    
3133 }