1 /*
   2  * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   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},
  50  * {@link DatatypeConstants#TIME time},
  51  * {@link DatatypeConstants#DATE date},
  52  * {@link DatatypeConstants#GYEARMONTH gYearMonth},
  53  * {@link DatatypeConstants#GMONTHDAY gMonthDay},
  54  * {@link DatatypeConstants#GYEAR gYear},
  55  * {@link DatatypeConstants#GMONTH gMonth} and
  56  * {@link DatatypeConstants#GDAY gDay}
  57  * defined in the XML Namespace
  58  * <code>"http://www.w3.org/2001/XMLSchema"</code>.
  59  * These datatypes are normatively defined in
  60  * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime">W3C XML Schema 1.0 Part 2, Section 3.2.7-14</a>.</p>
  61  *
  62  * <p>The table below defines the mapping between XML Schema 1.0
  63  * date/time datatype fields and this class' fields. It also summarizes
  64  * the value constraints for the date and time fields defined in
  65  * <a href="http://www.w3.org/TR/xmlschema-2/#isoformats">W3C XML Schema 1.0 Part 2, Appendix D,
  66  * <i>ISO 8601 Date and Time Formats</i></a>.</p>
  67  *
  68  * <a name="datetimefieldsmapping"/>
  69  * <table border="2" rules="all" cellpadding="2">
  70  *   <thead>
  71  *     <tr>
  72  *       <th align="center" colspan="3">
  73  *         Date/time datatype field mapping between XML Schema 1.0 and Java representation
  74  *       </th>
  75  *     </tr>
  76  *   </thead>
  77  *   <tbody>
  78  *     <tr>
  79  *       <th>XML Schema 1.0<br/>
  80  *           datatype<br/>
  81  *            field</th>
  82  *       <th>Related<br/>XMLGregorianCalendar<br/>Accessor(s)</th>
  83  *       <th>Value Range</th>
  84  *     </tr>
  85  *     <a name="datetimefield-year"/>
  86  *     <tr>
  87  *       <td> year </td>
  88  *       <td> {@link #getYear()} + {@link #getEon()} or<br/>
  89  *            {@link #getEonAndYear}
  90  *       </td>
  91  *       <td> <code>getYear()</code> is a value between -(10^9-1) to (10^9)-1
  92  *            or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
  93  *            {@link #getEon()} is high order year value in billion of years.<br/>
  94  *            <code>getEon()</code> has values greater than or equal to (10^9) or less than or equal to -(10^9).
  95  *            A value of null indicates field is undefined.</br>
  96  *            Given that <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-63">XML Schema 1.0 errata</a> states that the year zero
  97  *            will be a valid lexical value in a future version of XML Schema,
  98  *            this class allows the year field to be set to zero. Otherwise,
  99  *            the year field value is handled exactly as described
 100  *            in the errata and [ISO-8601-1988]. Note that W3C XML Schema 1.0
 101  *            validation does not allow for the year field to have a value of zero.
 102  *            </td>
 103  *     </tr>
 104  *     <a name="datetimefield-month"/>
 105  *     <tr>
 106  *       <td> month </td>
 107  *       <td> {@link #getMonth()} </td>
 108  *       <td> 1 to 12 or {@link DatatypeConstants#FIELD_UNDEFINED} </td>
 109  *     </tr>
 110  *     <a name="datetimefield-day"/>
 111  *     <tr>
 112  *       <td> day </td>
 113  *       <td> {@link #getDay()} </td>
 114  *       <td> Independent of month, max range is 1 to 31 or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
 115  *            The normative value constraint stated relative to month
 116  *            field's value is in <a href="http://www.w3.org/TR/xmlschema-2/#isoformats">W3C XML Schema 1.0 Part 2, Appendix D</a>.
 117  *       </td>
 118  *     </tr>
 119  *     <a name="datetimefield-hour"/>
 120  *     <tr>
 121  *       <td> hour </td>
 122  *       <td> {@link #getHour()} </td>
 123  *       <td>
 124  *         0 to 23 or {@link DatatypeConstants#FIELD_UNDEFINED}.
 125  *         An hour value of 24 is allowed to be set in the lexical space provided the minute and second
 126  *         field values are zero. However, an hour value of 24 is not allowed in value space and will be
 127  *         transformed to represent the value of the first instance of the following day as per
 128  *         <a href="http://www.w3.org/TR/xmlschema-2/#built-in-primitive-datatypes">
 129  *         XML Schema Part 2: Datatypes Second Edition, 3.2 Primitive datatypes</a>.
 130  *       </td>
 131  *     </tr>
 132  *     <a name="datetimefield-minute"/>
 133  *     <tr>
 134  *       <td> minute </td>
 135  *       <td> {@link #getMinute()} </td>
 136  *       <td> 0 to 59 or {@link DatatypeConstants#FIELD_UNDEFINED} </td>
 137  *     </tr>
 138  *     <a name="datetimefield-second"/>
 139  *     <tr>
 140  *       <td>second</td>
 141  *       <td>
 142  *         {@link #getSecond()} + {@link #getMillisecond()}/1000 or<br/>
 143  *         {@link #getSecond()} + {@link #getFractionalSecond()}
 144  *       </td>
 145  *       <td>
 146  *         {@link #getSecond()} from 0 to 60 or {@link DatatypeConstants#FIELD_UNDEFINED}.<br/>
 147  *         <i>(Note: 60 only allowable for leap second.)</i><br/>
 148  *         {@link #getFractionalSecond()} allows for infinite precision over the range from 0.0 to 1.0 when
 149  *         the {@link #getSecond()} is defined.<br/>
 150  *         <code>FractionalSecond</code> is optional and has a value of <code>null</code> when it is undefined.<br />
 151  *            {@link #getMillisecond()} is the convenience
 152  *            millisecond precision of value of {@link #getFractionalSecond()}.
 153  *       </td>
 154  *     </tr>
 155  *     <tr id="datetimefield-timezone">
 156  *       <td> timezone </td>
 157  *       <td> {@link #getTimezone()} </td>
 158  *       <td> Number of minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.
 159  *         Value range from -14 hours (-14 * 60 minutes) to 14 hours (14 * 60 minutes).
 160  *       </td>
 161  *     </tr>
 162  *   </tbody>
 163  *  </table>
 164  *
 165  * <p>All maximum value space constraints listed for the fields in the table
 166  * above are checked by factory methods, setter methods and parse methods of
 167  * this class. <code>IllegalArgumentException</code> is thrown when
 168  * parameter's value is outside the maximum value constraint for the field.
 169  * Validation checks, for example, whether days in month should be
 170  * limited to 29, 30 or 31 days, that are dependent on the values of other
 171  * fields are not checked by these methods.
 172  * </p>
 173  *
 174  * <p>The following operations are defined for this class:
 175  * <ul>
 176  *   <li>factory methods to create instances</li>
 177  *   <li>accessors/mutators for independent date/time fields</li>
 178  *   <li>conversion between this class and W3C XML Schema 1.0 lexical representation</li>
 179  *   <li>conversion between this class and <code>java.util.GregorianCalendar</code></li>
 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 
 231     /**
 232      * <p>Timezone of this <code>XMLGregorianCalendar</code> in minutes.</p>
 233      */
 234     private int timezone = DatatypeConstants.FIELD_UNDEFINED;
 235 
 236     /**
 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;
 287 
 288     /**
 289      * Hour index for MIN_ and MAX_FIELD_VALUES.
 290      */
 291     private static final int HOUR   = 3;
 292 
 293     /**
 294      * Minute index for MIN_ and MAX_FIELD_VALUES.
 295      */
 296     private static final int MINUTE = 4;
 297 
 298     /**
 299      * Second index for MIN_ and MAX_FIELD_VALUES.
 300      */
 301     private static final int SECOND = 5;
 302 
 303     /**
 304      * Second index for MIN_ and MAX_FIELD_VALUES.
 305      */
 306     private static final int MILLISECOND = 6;
 307 
 308     /**
 309      * Timezone index for MIN_ and MAX_FIELD_VALUES
 310      */
 311     private static final int TIMEZONE = 7;
 312 
 313 
 314     /**
 315      * field names indexed by YEAR..TIMEZONE.
 316      */
 317     private static final String FIELD_NAME[] = {
 318         "Year",
 319         "Month",
 320         "Day",
 321         "Hour",
 322         "Minute",
 323         "Second",
 324         "Millisecond",
 325         "Timezone"
 326     };
 327 
 328     /**
 329      * <p>Stream Unique Identifier.</p>
 330      *
 331      * <p>TODO: Serialization should use the XML string representation as
 332      * the serialization format to ensure future compatibility.</p>
 333      */
 334     private static final long serialVersionUID = 1L;
 335 
 336     /**
 337      * <p>Use as a template for default field values when
 338      * converting to a {@link GregorianCalendar}, set to a leap
 339      * year date of January 1, 0400 at midnight.</p>
 340      *
 341      * <p>Fields that are optional for an <code>xsd:dateTime</code> instances are defaulted to not being set to any value.
 342      * <code>XMLGregorianCalendar</code> fields millisecond, fractional second and timezone return the value indicating
 343      * that the field is not set, {@link DatatypeConstants#FIELD_UNDEFINED} for millisecond and timezone
 344      * and <code>null</code> for fractional second.</p>
 345      *
 346      * @see #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)
 347      */
 348     public static final XMLGregorianCalendar LEAP_YEAR_DEFAULT =
 349                 createDateTime(
 350                         400,  //year
 351                 DatatypeConstants.JANUARY,  //month
 352                         1,  // day
 353                     0,  // hour
 354                     0,  // minute
 355                     0,  // second
 356                     DatatypeConstants.FIELD_UNDEFINED,  // milliseconds
 357                     DatatypeConstants.FIELD_UNDEFINED // timezone
 358                 );
 359 
 360     // Constructors
 361 
 362     /**
 363      * Constructs a new XMLGregorianCalendar object.
 364      *
 365      * String parsing documented by {@link #parse(String)}.
 366      *
 367      * Returns a non-null valid XMLGregorianCalendar object that holds the
 368      * value indicated by the lexicalRepresentation parameter.
 369      *
 370      * @param lexicalRepresentation
 371      *      Lexical representation of one the eight
 372      *      XML Schema date/time datatypes.
 373      * @throws IllegalArgumentException
 374      *      If the given string does not conform as documented in
 375      *      {@link #parse(String)}.
 376      * @throws NullPointerException
 377      *      If the given string is null.
 378      */
 379     protected XMLGregorianCalendarImpl(String lexicalRepresentation)
 380             throws IllegalArgumentException {
 381 
 382         // compute format string for this lexical representation.
 383         String format = null;
 384         String lexRep = lexicalRepresentation;
 385         final int NOT_FOUND = -1;
 386         int lexRepLength = lexRep.length();
 387 
 388         // current parser needs a format string,
 389         // use following heuristics to figure out what xml schema date/time
 390         // datatype this lexical string could represent.
 391         // Fix 4971612: invalid SCCS macro substitution in data string,
 392         //   no %{alpha}% to avoid SCCS maco substitution
 393         if (lexRep.indexOf('T') != NOT_FOUND) {
 394             // found Date Time separater, must be xsd:DateTime
 395             format = "%Y-%M-%DT%h:%m:%s" + "%z";
 396         } else if (lexRepLength >= 3 && lexRep.charAt(2) == ':') {
 397             // found ":", must be xsd:Time
 398             format = "%h:%m:%s" + "%z";
 399         } else if (lexRep.startsWith("--")) {
 400             // check for gDay || gMonth || gMonthDay
 401             if (lexRepLength >= 3 && lexRep.charAt(2) == '-') {
 402                 // gDay, ---DD(z?)
 403                 format = "---%D" + "%z";
 404             } else if (lexRepLength == 4     // --MM
 405                     || lexRepLength == 5     // --MMZ
 406                     || lexRepLength == 10) { // --MMSHH:MM
 407                 // gMonth, --MM(z?),
 408                 // per XML Schema Errata, used to be --MM--(z?)
 409                 format = "--%M" + "%z";
 410             } else {
 411                 // gMonthDay, --MM-DD(z?), (or invalid lexicalRepresentation)
 412                 // length should be:
 413                 //  7: --MM-DD
 414                 //  8: --MM-DDZ
 415                 // 13: --MM-DDSHH:MM
 416                 format = "--%M-%D" + "%z";
 417             }
 418         } else {
 419             // check for Date || GYear | GYearMonth
 420             int countSeparator = 0;
 421 
 422             // start at index 1 to skip potential negative sign for year.
 423 
 424 
 425             int timezoneOffset = lexRep.indexOf(':');
 426             if (timezoneOffset != NOT_FOUND) {
 427 
 428                 // found timezone, strip it off for distinguishing
 429                 // between Date, GYear and GYearMonth so possible
 430                 // negative sign in timezone is not mistaken as
 431                 // a separator.
 432                 lexRepLength -= 6;
 433             }
 434 
 435             for (int i = 1; i < lexRepLength; i++) {
 436                 if (lexRep.charAt(i) == '-') {
 437                     countSeparator++;
 438                 }
 439             }
 440             if (countSeparator == 0) {
 441                 // GYear
 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.
 502      * @param second of <code>XMLGregorianCalendar</code> to be created.
 503      * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
 504      * @param timezone of <code>XMLGregorianCalendar</code> to be created.
 505      *
 506      */
 507     protected XMLGregorianCalendarImpl(
 508         BigInteger year,
 509         int month,
 510         int day,
 511         int hour,
 512         int minute,
 513         int second,
 514         BigDecimal fractionalSecond,
 515         int timezone) {
 516 
 517         setYear(year);
 518         setMonth(month);
 519         setDay(day);
 520         setTime(hour, minute, second, fractionalSecond);
 521         setTimezone(timezone);
 522 
 523         // check for validity
 524         if (!isValid()) {
 525 
 526             throw new IllegalArgumentException(
 527                 DatatypeMessageFormatter.formatMessage(null,
 528                     "InvalidXGCValue-fractional",
 529                     new Object[] { year, new Integer(month), new Integer(day),
 530                     new Integer(hour), new Integer(minute), new Integer(second),
 531                     fractionalSecond, new Integer(timezone)})
 532                         );
 533 
 534                         /**
 535                 String yearString = "null";
 536                 if (year != null) {
 537                     yearString = year.toString();
 538                 }
 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>
 646          *     <tr>
 647          *       <th>{@link #setYear(int)}</th>
 648          *       <th><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></th>
 649          *     </tr>
 650          *     <tr>
 651          *       <th>{@link #setMonth(int)}</th>
 652          *       <th><code>MONTH + 1</code></th>
 653          *     </tr>
 654          *     <tr>
 655          *       <th>{@link #setDay(int)}</th>
 656          *       <th><code>DAY_OF_MONTH</code></th>
 657          *     </tr>
 658          *     <tr>
 659          *       <th>{@link #setTime(int,int,int, BigDecimal)}</th>
 660          *       <th><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></th>
 661          *     </tr>
 662          *     <tr>
 663          *       <th>{@link #setTimezone(int)}<i>*</i></th>
 664          *       <th><code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
 665          *       <i>(in minutes)</i>
 666          *       </th>
 667          *     </tr>
 668          *   </tbody>
 669          * </table>
 670          * <p><i>*</i>conversion loss of information. It is not possible to represent
 671          * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
 672          * XML Schema 1.0 date/time datatype representation.</p>
 673          *
 674          * <p>To compute the return value's <code>TimeZone</code> field,
 675          * <ul>
 676          * <li>when <code>this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
 677          * create a <code>java.util.TimeZone</code> with a custom timezone id
 678          * using the <code>this.getTimezone()</code>.</li>
 679          * <li>else use the <code>GregorianCalendar</code> default timezone value
 680          * for the host is defined as specified by
 681          * <code>java.util.TimeZone.getDefault()</code>.</li></p>
 682          *
 683          * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
 684          */
 685     public XMLGregorianCalendarImpl(GregorianCalendar cal) {
 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
 727      *
 728      * @throws IllegalArgumentException if any parameter is outside value
 729      * constraints for the field as specified in
 730      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
 731      */
 732     public static XMLGregorianCalendar createDateTime(
 733         BigInteger year,
 734         int month,
 735         int day,
 736         int hours,
 737         int minutes,
 738         int seconds,
 739         BigDecimal fractionalSecond,
 740         int timezone) {
 741 
 742         return new XMLGregorianCalendarImpl(
 743             year,
 744             month,
 745             day,
 746             hours,
 747             minutes,
 748             seconds,
 749             fractionalSecond,
 750             timezone);
 751     }
 752 
 753     /**
 754      * <p>Create a Java instance of XML Schema builtin datatype dateTime.</p>
 755      *
 756      * @param year represents both high-order eons and low-order year.
 757      * @param month of <code>dateTime</code>
 758      * @param day of <code>dateTime</code>
 759      * @param hour of <code>dateTime</code>
 760      * @param minute of <code>dateTime</code>
 761      * @param second of <code>dateTime</code>
 762      *
 763      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 764      *
 765      * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in
 766      *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
 767      *
 768      * @see DatatypeConstants#FIELD_UNDEFINED
 769      */
 770     public static XMLGregorianCalendar createDateTime(
 771         int year,
 772         int month,
 773         int day,
 774         int hour,
 775         int minute,
 776         int second) {
 777 
 778         return new XMLGregorianCalendarImpl(
 779             year,
 780             month,
 781             day,
 782             hour,
 783             minute,
 784             second,
 785             DatatypeConstants.FIELD_UNDEFINED,  //millisecond
 786                 DatatypeConstants.FIELD_UNDEFINED //timezone
 787         );
 788     }
 789 
 790     /**
 791      * <p>Create a Java representation of XML Schema builtin datatype <code>dateTime</code>.
 792      * All possible fields are specified for this factory method.</p>
 793      *
 794      * @param year represents low-order year.
 795      * @param month of <code>dateTime</code>
 796      * @param day of <code>dateTime</code>
 797      * @param hours of <code>dateTime</code>
 798      * @param minutes of <code>dateTime</code>
 799      * @param seconds of <code>dateTime</code>
 800      * @param milliseconds of <code>dateTime</code>. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 801      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 802      *
 803      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 804      *
 805      * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in
 806      *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
 807      *
 808      * @see DatatypeConstants#FIELD_UNDEFINED
 809      */
 810     public static XMLGregorianCalendar createDateTime(
 811         int year,
 812         int month,
 813         int day,
 814         int hours,
 815         int minutes,
 816         int seconds,
 817         int milliseconds,
 818         int timezone) {
 819 
 820         return new XMLGregorianCalendarImpl(
 821             year,
 822             month,
 823             day,
 824             hours,
 825             minutes,
 826             seconds,
 827             milliseconds,
 828             timezone);
 829     }
 830 
 831     /**
 832      * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
 833      *
 834      * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
 835      * with <code>month</code> and <code>day</code> parameters set to
 836      * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
 837      *
 838      * @param year of <code>XMLGregorianCalendar</code> to be created.
 839      * @param month of <code>XMLGregorianCalendar</code> to be created.
 840      * @param day of <code>XMLGregorianCalendar</code> to be created.
 841      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 842      *
 843      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 844      *
 845      * @see DatatypeConstants#FIELD_UNDEFINED
 846      *
 847      * @throws IllegalArgumentException if any parameter is outside value
 848      * constraints for the field as specified in
 849      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
 850      */
 851     public static XMLGregorianCalendar createDate(
 852         int year,
 853         int month,
 854         int day,
 855         int timezone) {
 856 
 857         return new XMLGregorianCalendarImpl(
 858             year,
 859             month,
 860             day,
 861             DatatypeConstants.FIELD_UNDEFINED, // hour
 862             DatatypeConstants.FIELD_UNDEFINED, // minute
 863             DatatypeConstants.FIELD_UNDEFINED, // second
 864                 DatatypeConstants.FIELD_UNDEFINED, // millisecond
 865             timezone);
 866     }
 867 
 868     /**
 869      * Create a Java instance of XML Schema builtin datatype <code>time</code>.
 870      * @param hours number of hours
 871      * @param minutes number of minutes
 872      * @param seconds number of seconds
 873      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 874      *
 875      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 876      *
 877      * @see DatatypeConstants#FIELD_UNDEFINED
 878      *
 879      * @throws IllegalArgumentException if any parameter is outside value
 880      * constraints for the field as specified in
 881      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
 882      */
 883     public static XMLGregorianCalendar createTime(
 884         int hours,
 885         int minutes,
 886         int seconds,
 887                 int timezone) {
 888 
 889                 return new XMLGregorianCalendarImpl(
 890                         DatatypeConstants.FIELD_UNDEFINED, // Year
 891                         DatatypeConstants.FIELD_UNDEFINED, // Month
 892                         DatatypeConstants.FIELD_UNDEFINED, // Day
 893                         hours,
 894                         minutes,
 895                         seconds,
 896                         DatatypeConstants.FIELD_UNDEFINED, //Millisecond
 897                         timezone);
 898     }
 899 
 900     /**
 901      * <p>Create a Java instance of XML Schema builtin datatype time.</p>
 902      *
 903      * @param hours number of hours
 904      * @param minutes number of minutes
 905      * @param seconds number of seconds
 906      * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
 907      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 908      *
 909      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 910      *
 911      * @see DatatypeConstants#FIELD_UNDEFINED
 912      *
 913      * @throws IllegalArgumentException if any parameter is outside value
 914      * constraints for the field as specified in
 915      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
 916      */
 917     public static XMLGregorianCalendar createTime(
 918         int hours,
 919         int minutes,
 920         int seconds,
 921         BigDecimal fractionalSecond,
 922         int timezone) {
 923 
 924         return new XMLGregorianCalendarImpl(
 925             null,            // Year
 926             DatatypeConstants.FIELD_UNDEFINED, // month
 927             DatatypeConstants.FIELD_UNDEFINED, // day
 928             hours,
 929             minutes,
 930             seconds,
 931             fractionalSecond,
 932             timezone);
 933     }
 934 
 935     /**
 936      * <p>Create a Java instance of XML Schema builtin datatype time.</p>
 937      *
 938      * @param hours number of hours
 939      * @param minutes number of minutes
 940      * @param seconds number of seconds
 941      * @param milliseconds number of milliseconds
 942      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
 943      *
 944      * @return <code>XMLGregorianCalendar</code> created from parameter values.
 945      *
 946      * @see DatatypeConstants#FIELD_UNDEFINED
 947      *
 948      * @throws IllegalArgumentException if any parameter is outside value
 949      * constraints for the field as specified in
 950      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
 951      */
 952     public static XMLGregorianCalendar createTime(
 953         int hours,
 954         int minutes,
 955         int seconds,
 956         int milliseconds,
 957         int timezone) {
 958 
 959         return new XMLGregorianCalendarImpl(
 960                 DatatypeConstants.FIELD_UNDEFINED, // year
 961                 DatatypeConstants.FIELD_UNDEFINED, // month
 962                 DatatypeConstants.FIELD_UNDEFINED, // day
 963                 hours,
 964                 minutes,
 965                 seconds,
 966                 milliseconds,
 967                 timezone);
 968     }
 969 
 970     // Accessors
 971 
 972     /**
 973      * <p>Return high order component for XML Schema 1.0 dateTime datatype field for
 974      * <code>year</code>.
 975      * <code>null</code> if this optional part of the year field is not defined.</p>
 976      *
 977      * <p>Value constraints for this value are summarized in
 978      * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
 979      * @return eon of this <code>XMLGregorianCalendar</code>. The value
 980      * returned is an integer multiple of 10^9.
 981      *
 982      * @see #getYear()
 983      * @see #getEonAndYear()
 984      */
 985     public BigInteger getEon() {
 986            return eon;
 987     }
 988 
 989     /**
 990      * <p>Return low order component for XML Schema 1.0 dateTime datatype field for
 991      * <code>year</code> or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
 992      *
 993      * <p>Value constraints for this value are summarized in
 994      * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
 995      *
 996      * @return year  of this <code>XMLGregorianCalendar</code>.
 997      *
 998      * @see #getEon()
 999      * @see #getEonAndYear()
1000      */
1001     public int getYear() {
1002            return year;
1003     }
1004 
1005     /**
1006      * <p>Return XML Schema 1.0 dateTime datatype field for
1007      * <code>year</code>.</p>
1008      *
1009      * <p>Value constraints for this value are summarized in
1010      * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
1011      *
1012      * @return sum of <code>eon</code> and <code>BigInteger.valueOf(year)</code>
1013      * when both fields are defined. When only <code>year</code> is defined,
1014      * return it. When both <code>eon</code> and <code>year</code> are not
1015      * defined, return <code>null</code>.
1016      *
1017      * @see #getEon()
1018      * @see #getYear()
1019      */
1020     public BigInteger getEonAndYear() {
1021 
1022                 // both are defined
1023                 if (year != DatatypeConstants.FIELD_UNDEFINED
1024                         && eon != null) {
1025 
1026                         return eon.add(BigInteger.valueOf((long) year));
1027                 }
1028 
1029                 // only year is defined
1030                 if (year != DatatypeConstants.FIELD_UNDEFINED
1031                         && eon == null) {
1032 
1033                         return BigInteger.valueOf((long) year);
1034                 }
1035 
1036         // neither are defined
1037         // or only eon is defined which is not valid without a year
1038                 return null;
1039     }
1040 
1041     /**
1042      * <p>Return number of month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1043      *
1044      * <p>Value constraints for this value are summarized in
1045      * <a href="#datetimefield-month">month field of date/time field mapping table</a>.</p>
1046      *
1047      * @return year  of this <code>XMLGregorianCalendar</code>.
1048      *
1049      */
1050     public int getMonth() {
1051         return month;
1052     }
1053 
1054     /**
1055      * Return day in month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1056      *
1057      * <p>Value constraints for this value are summarized in
1058      * <a href="#datetimefield-day">day field of date/time field mapping table</a>.</p>
1059      *
1060      * @see #setDay(int)
1061      */
1062     public int getDay() {
1063         return day;
1064     }
1065 
1066     /**
1067      * Return timezone offset in minutes or
1068      * {@link DatatypeConstants#FIELD_UNDEFINED} if this optional field is not defined.
1069      *
1070      * <p>Value constraints for this value are summarized in
1071      * <a href="#datetimefield-timezone">timezone field of date/time field mapping table</a>.</p>
1072      *
1073      * @see #setTimezone(int)
1074      */
1075     public int getTimezone() {
1076         return timezone;
1077     }
1078 
1079     /**
1080      * Return hours or {@link DatatypeConstants#FIELD_UNDEFINED}.
1081      * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1082      *
1083      * <p>Value constraints for this value are summarized in
1084      * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.</p>
1085      * @see #setTime(int, int, int)
1086      */
1087     public int getHour() {
1088         return hour;
1089     }
1090 
1091     /**
1092      * Return minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p>
1093      * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1094      *
1095      * <p>Value constraints for this value are summarized in
1096      * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.</p>
1097      * @see #setTime(int, int, int)
1098      */
1099     public int getMinute() {
1100         return minute;
1101     }
1102 
1103     /**
1104      * <p>Return seconds or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p>
1105      *
1106      * <p>Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1107      * When this field is not defined, the optional xs:dateTime
1108      * fractional seconds field, represented by
1109      * {@link #getFractionalSecond()} and {@link #getMillisecond()},
1110      * must not be defined.</p>
1111      *
1112      * <p>Value constraints for this value are summarized in
1113      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1114      *
1115      * @return Second  of this <code>XMLGregorianCalendar</code>.
1116      *
1117      * @see #getFractionalSecond()
1118      * @see #getMillisecond()
1119      * @see #setTime(int, int, int)
1120      */
1121     public int getSecond() {
1122            return second;
1123     }
1124 
1125     /**
1126      * @return result of adding second and fractional second field
1127      */
1128     private BigDecimal getSeconds() {
1129         if (second == DatatypeConstants.FIELD_UNDEFINED) {
1130             return DECIMAL_ZERO;
1131         }
1132         BigDecimal result = BigDecimal.valueOf((long) second);
1133         if (fractionalSecond != null) {
1134             return result.add(fractionalSecond);
1135         } else {
1136             return result;
1137         }
1138     }
1139 
1140 
1141     /**
1142      * <p>Return millisecond precision of {@link #getFractionalSecond()}.<\p>
1143      *
1144      * <p>This method represents a convenience accessor to infinite
1145      * precision fractional second value returned by
1146      * {@link #getFractionalSecond()}. The returned value is the rounded
1147      * down to milliseconds value of
1148      * {@link #getFractionalSecond()}. When {@link #getFractionalSecond()}
1149      * returns <code>null</code>, this method must return
1150      * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1151      *
1152      * <p>Value constraints for this value are summarized in
1153      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1154      *
1155      * @return Millisecond  of this <code>XMLGregorianCalendar</code>.
1156      *
1157      * @see #getFractionalSecond()
1158      * @see #setTime(int, int, int)
1159      */
1160     public int getMillisecond() {
1161         if (fractionalSecond == null) {
1162             return DatatypeConstants.FIELD_UNDEFINED;
1163         } else {
1164             // TODO: Non-optimal solution for now.
1165             // Efficient implementation would only store as BigDecimal
1166             // when needed and millisecond otherwise.
1167             return fractionalSecond.movePointRight(3).intValue();
1168         }
1169     }
1170 
1171     /**
1172      * <p>Return fractional seconds.</p>
1173      *
1174      * <p><code>null</code> is returned when this optional field is not defined.</p>
1175      *
1176      * <p>Value constraints are detailed in
1177      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1178      *
1179      * <p>This optional field can only have a defined value when the
1180      * xs:dateTime second field, represented by ({@link #getSecond()},
1181      * does not return {@link DatatypeConstants#FIELD_UNDEFINED}).</p>
1182      *
1183      * @return fractional seconds  of this <code>XMLGregorianCalendar</code>.
1184      *
1185      * @see #getSecond()
1186      * @see #setTime(int, int, int, BigDecimal)
1187      */
1188     public BigDecimal getFractionalSecond() {
1189            return fractionalSecond;
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         }
1260     }
1261 
1262     /**
1263      * <p>Set month.</p>
1264      *
1265      * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1266      *
1267      * @param month value constraints summarized in <a href="#datetimefield-month">month field of date/time field mapping table</a>.
1268      *
1269      * @throws IllegalArgumentException if <code>month</code> parameter is
1270      * outside value constraints for the field as specified in
1271      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1272      */
1273     public void setMonth(int month) {
1274         if(month<DatatypeConstants.JANUARY || DatatypeConstants.DECEMBER<month)
1275             if(month!=DatatypeConstants.FIELD_UNDEFINED)
1276                 invalidFieldValue(MONTH, month);
1277         this.month = month;
1278     }
1279 
1280     /**
1281      * <p>Set days in month.</p>
1282      *
1283      * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1284      *
1285      * @param day value constraints summarized in <a href="#datetimefield-day">day field of date/time field mapping table</a>.
1286      *
1287      * @throws IllegalArgumentException if <code>day</code> parameter is
1288      * outside value constraints for the field as specified in
1289      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1290      */
1291     public void setDay(int day) {
1292         if(day<1 || 31<day)
1293             if(day!=DatatypeConstants.FIELD_UNDEFINED)
1294                 invalidFieldValue(DAY,day);
1295         this.day = day;
1296     }
1297 
1298     /**
1299      * <p>Set the number of minutes in the timezone offset.</p>
1300      *
1301      * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1302      *
1303      * @param offset value constraints summarized in <a href="#datetimefield-timezone">
1304      *   timezone field of date/time field mapping table</a>.
1305      *
1306      * @throws IllegalArgumentException if <code>offset</code> parameter is
1307      * outside value constraints for the field as specified in
1308      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1309      */
1310     public void setTimezone(int offset) {
1311             if(offset<-14*60 || 14*60<offset)
1312             if(offset!=DatatypeConstants.FIELD_UNDEFINED)
1313                 invalidFieldValue(TIMEZONE,offset);
1314         this.timezone = offset;
1315     }
1316 
1317     /**
1318      * <p>Set time as one unit.</p>
1319      *
1320      * @param hour value constraints are summarized in
1321      * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1322      * @param minute value constraints are summarized in
1323      * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1324      * @param second value constraints are summarized in
1325      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1326      *
1327      * @see #setTime(int, int, int, BigDecimal)
1328      *
1329      * @throws IllegalArgumentException if any parameter is
1330      * outside value constraints for the field as specified in
1331      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1332      */
1333     public void setTime(int hour, int minute, int second) {
1334         setTime(hour, minute, second, null);
1335     }
1336 
1337     private void invalidFieldValue(int field, int value) {
1338         throw new IllegalArgumentException(
1339             DatatypeMessageFormatter.formatMessage(null, "InvalidFieldValue",
1340                 new Object[]{ new Integer(value), FIELD_NAME[field]})
1341         );
1342     }
1343 
1344     private void testHour() {
1345 
1346         // http://www.w3.org/2001/05/xmlschema-errata#e2-45
1347         if (getHour() == 24) {
1348             if (getMinute() != 0
1349                     || getSecond() != 0) {
1350                 invalidFieldValue(HOUR, getHour());
1351             }
1352             // while 0-24 is acceptable in the lexical space, 24 is not valid in value space
1353             // W3C XML Schema Part 2, Section 3.2.7.1
1354             setHour(0, false);
1355             add(new DurationImpl(true, 0, 0, 1, 0, 0, 0));
1356         }
1357     }
1358 
1359     public void setHour(int hour) {
1360 
1361         setHour(hour, true);
1362     }
1363 
1364     private void setHour(int hour, boolean validate) {
1365 
1366         if (hour < 0 || hour > 24) {
1367             if (hour != DatatypeConstants.FIELD_UNDEFINED) {
1368                 invalidFieldValue(HOUR, hour);
1369             }
1370         }
1371 
1372         this.hour = hour;
1373 
1374         if (validate) {
1375             testHour();
1376         }
1377     }
1378 
1379     public void setMinute(int minute) {
1380         if(minute<0 || 59<minute)
1381             if(minute!=DatatypeConstants.FIELD_UNDEFINED)
1382                 invalidFieldValue(MINUTE, minute);
1383         this.minute = minute;
1384     }
1385 
1386     public void setSecond(int second) {
1387         if(second<0 || 60<second)   // leap second allows for 60
1388             if(second!=DatatypeConstants.FIELD_UNDEFINED)
1389                 invalidFieldValue(SECOND, second);
1390         this.second  = second;
1391     }
1392 
1393     /**
1394      * <p>Set time as one unit, including the optional infinite precison
1395      * fractional seconds.</p>
1396      *
1397      * @param hour value constraints are summarized in
1398      * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1399      * @param minute value constraints are summarized in
1400      * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1401      * @param second value constraints are summarized in
1402      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1403      * @param fractional value of <code>null</code> indicates this optional
1404      *                   field is not set.
1405      *
1406      * @throws IllegalArgumentException if any parameter is
1407      * outside value constraints for the field as specified in
1408      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1409      */
1410     public void setTime(
1411             int hour,
1412             int minute,
1413             int second,
1414             BigDecimal fractional) {
1415 
1416         setHour(hour, false);
1417 
1418         setMinute(minute);
1419         if (second != 60) {
1420             setSecond(second);
1421         } else if ((hour == 23 && minute == 59) || (hour == 0 && minute == 0)) {
1422             setSecond(second);
1423         } else {
1424             invalidFieldValue(SECOND, second);
1425         }
1426 
1427         setFractionalSecond(fractional);
1428 
1429         // must test hour after setting seconds
1430         testHour();
1431     }
1432 
1433 
1434     /**
1435      * <p>Set time as one unit, including optional milliseconds.</p>
1436      *
1437      * @param hour value constraints are summarized in
1438      * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1439      * @param minute value constraints are summarized in
1440      * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1441      * @param second value constraints are summarized in
1442      * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1443      * @param millisecond value of {@link DatatypeConstants#FIELD_UNDEFINED} indicates this
1444      *                    optional field is not set.
1445      *
1446      * @throws IllegalArgumentException if any parameter is
1447      * outside value constraints for the field as specified in
1448      * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1449      */
1450     public void setTime(int hour, int minute, int second, int millisecond) {
1451 
1452         setHour(hour, false);
1453 
1454         setMinute(minute);
1455         if (second != 60) {
1456             setSecond(second);
1457         } else if ((hour == 23 && minute == 59) || (hour == 0 && minute == 0)) {
1458             setSecond(second);
1459         } else {
1460             invalidFieldValue(SECOND, second);
1461         }
1462         setMillisecond(millisecond);
1463 
1464         // must test hour after setting seconds
1465         testHour();
1466     }
1467 
1468     // comparisons
1469     /**
1470      * <p>Compare two instances of W3C XML Schema 1.0 date/time datatypes
1471      * according to partial order relation defined in
1472      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.3,
1473      * <i>Order relation on dateTime</i></a>.</p>
1474      *
1475      * <p><code>xsd:dateTime</code> datatype field mapping to accessors of
1476      * this class are defined in
1477      * <a href="#datetimefieldmapping">date/time field mapping table</a>.</p>
1478      *
1479      * @param rhs instance of <code>XMLGregorianCalendar</code> to compare
1480      *
1481      * @return the relationship between <code>lhs</code> and <code>rhs</code> as
1482      *   {@link DatatypeConstants#LESSER},
1483      *   {@link DatatypeConstants#EQUAL},
1484      *   {@link DatatypeConstants#GREATER} or
1485      *   {@link DatatypeConstants#INDETERMINATE}.
1486      *
1487      * @throws NullPointerException if <code>lhs</code> or <code>rhs</code>
1488      * parameters are null.
1489      */
1490     public int compare(XMLGregorianCalendar rhs) {
1491 
1492         XMLGregorianCalendar lhs = this;
1493 
1494         int result = DatatypeConstants.INDETERMINATE;
1495         XMLGregorianCalendarImpl P = (XMLGregorianCalendarImpl) lhs;
1496         XMLGregorianCalendarImpl Q = (XMLGregorianCalendarImpl) rhs;
1497 
1498         if (P.getTimezone() == Q.getTimezone()) {
1499             // Optimization:
1500             // both instances are in same timezone or
1501             // both are FIELD_UNDEFINED.
1502             // Avoid costly normalization of timezone to 'Z' time.
1503             return internalCompare(P, Q);
1504 
1505         } else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED &&
1506                 Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
1507 
1508             // Both instances have different timezones.
1509             // Normalize to UTC time and compare.
1510             P = (XMLGregorianCalendarImpl) P.normalize();
1511             Q = (XMLGregorianCalendarImpl) Q.normalize();
1512             return internalCompare(P, Q);
1513         } else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
1514 
1515             if (P.getTimezone() != 0) {
1516                 P = (XMLGregorianCalendarImpl) P.normalize();
1517             }
1518 
1519             // C. step 1
1520             XMLGregorianCalendar MinQ = Q.normalizeToTimezone(DatatypeConstants.MIN_TIMEZONE_OFFSET);
1521             result = internalCompare(P, MinQ);
1522             if (result == DatatypeConstants.LESSER) {
1523                 return result;
1524             }
1525 
1526             // C. step 2
1527             XMLGregorianCalendar MaxQ = Q.normalizeToTimezone(DatatypeConstants.MAX_TIMEZONE_OFFSET);
1528             result = internalCompare(P, MaxQ);
1529             if (result == DatatypeConstants.GREATER) {
1530                 return result;
1531             } else {
1532                 // C. step 3
1533                 return DatatypeConstants.INDETERMINATE;
1534             }
1535         } else { // Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
1536             // P has no timezone and Q does.
1537             if (Q.getTimezone() != 0) {
1538                 Q = (XMLGregorianCalendarImpl) Q.normalizeToTimezone(Q.getTimezone());
1539             }
1540 
1541             // D. step 1
1542             XMLGregorianCalendar MaxP = P.normalizeToTimezone(DatatypeConstants.MAX_TIMEZONE_OFFSET);
1543             result = internalCompare(MaxP, Q);
1544             if (result == DatatypeConstants.LESSER) {
1545                 return result;
1546             }
1547 
1548             // D. step 2
1549             XMLGregorianCalendar MinP = P.normalizeToTimezone(DatatypeConstants.MIN_TIMEZONE_OFFSET);
1550             result = internalCompare(MinP, Q);
1551             if (result == DatatypeConstants.GREATER) {
1552                 return result;
1553             } else {
1554                 // D. step 3
1555                 return DatatypeConstants.INDETERMINATE;
1556             }
1557         }
1558     }
1559 
1560     /**
1561      * <p>Normalize this instance to UTC.</p>
1562      *
1563      * <p>2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z</p>
1564      * <p>Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).</p>
1565      */
1566     public XMLGregorianCalendar normalize() {
1567 
1568         XMLGregorianCalendar normalized = normalizeToTimezone(timezone);
1569 
1570         // if timezone was undefined, leave it undefined
1571         if (getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
1572             normalized.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
1573         }
1574 
1575         // if milliseconds was undefined, leave it undefined
1576         if (getMillisecond() == DatatypeConstants.FIELD_UNDEFINED) {
1577             normalized.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
1578         }
1579 
1580         return normalized;
1581     }
1582 
1583         /**
1584          * <p>Normalize this instance to UTC.</p>
1585          *
1586          * <p>2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z</p>
1587          * <p>Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).</p>
1588          */
1589     private XMLGregorianCalendar normalizeToTimezone(int timezone) {
1590 
1591         int minutes = timezone;
1592         XMLGregorianCalendar result = (XMLGregorianCalendar) this.clone();
1593 
1594         // normalizing to UTC time negates the timezone offset before
1595         // addition.
1596         minutes = -minutes;
1597         Duration d = new DurationImpl(minutes >= 0, // isPositive
1598                 0, //years
1599                 0, //months
1600                 0, //days
1601                 0, //hours
1602                 minutes < 0 ? -minutes : minutes, // absolute
1603                 0  //seconds
1604         );
1605         result.add(d);
1606 
1607         // set to zulu UTC time.
1608         result.setTimezone(0);
1609         return result;
1610     }
1611 
1612     /**
1613      *
1614      *  <p>Implements Step B from http://www.w3.org/TR/xmlschema-2/#dateTime-order </p>
1615      * @param P calendar instance with normalized timezone offset or
1616      *          having same timezone as Q
1617      * @param Q calendar instance with normalized timezone offset or
1618      *          having same timezone as P
1619      *
1620      * @return result of comparing P and Q, value of
1621      *   {@link DatatypeConstants#EQUAL},
1622      *   {@link DatatypeConstants#LESSER},
1623      *   {@link DatatypeConstants#GREATER} or
1624      *   {@link DatatypeConstants#INDETERMINATE}.
1625      */
1626     private static int internalCompare(XMLGregorianCalendar P,
1627                                        XMLGregorianCalendar Q) {
1628 
1629         int result;
1630 
1631         // compare Year.
1632         if (P.getEon() == Q.getEon()) {
1633 
1634             // Eon field is only equal when null.
1635             // optimized case for comparing year not requiring eon field.
1636             result = compareField(P.getYear(), Q.getYear());
1637             if (result != DatatypeConstants.EQUAL) {
1638                 return result;
1639             }
1640         } else {
1641             result = compareField(P.getEonAndYear(), Q.getEonAndYear());
1642             if (result != DatatypeConstants.EQUAL) {
1643                 return result;
1644             }
1645         }
1646 
1647         result = compareField(P.getMonth(), Q.getMonth());
1648         if (result != DatatypeConstants.EQUAL) {
1649             return result;
1650         }
1651 
1652         result = compareField(P.getDay(), Q.getDay());
1653         if (result != DatatypeConstants.EQUAL) {
1654             return result;
1655         }
1656 
1657         result = compareField(P.getHour(), Q.getHour());
1658         if (result != DatatypeConstants.EQUAL) {
1659             return result;
1660         }
1661 
1662         result = compareField(P.getMinute(), Q.getMinute());
1663         if (result != DatatypeConstants.EQUAL) {
1664             return result;
1665         }
1666         result = compareField(P.getSecond(), Q.getSecond());
1667         if (result != DatatypeConstants.EQUAL) {
1668             return result;
1669         }
1670 
1671         result = compareField(P.getFractionalSecond(), Q.getFractionalSecond());
1672         return result;
1673     }
1674 
1675     /**
1676      * <p>Implement Step B from
1677      * http://www.w3.org/TR/xmlschema-2/#dateTime-order.</p>
1678      */
1679     private static int compareField(int Pfield, int Qfield) {
1680         if (Pfield == Qfield) {
1681 
1682             //fields are either equal in value or both undefined.
1683             // Step B. 1.1 AND optimized result of performing 1.1-1.4.
1684             return DatatypeConstants.EQUAL;
1685         } else {
1686             if (Pfield == DatatypeConstants.FIELD_UNDEFINED || Qfield == DatatypeConstants.FIELD_UNDEFINED) {
1687                 // Step B. 1.2
1688                 return DatatypeConstants.INDETERMINATE;
1689             } else {
1690                 // Step B. 1.3-4.
1691                 return (Pfield < Qfield ? DatatypeConstants.LESSER : DatatypeConstants.GREATER);
1692             }
1693         }
1694     }
1695 
1696     private static int compareField(BigInteger Pfield, BigInteger Qfield) {
1697         if (Pfield == null) {
1698             return (Qfield == null ? DatatypeConstants.EQUAL : DatatypeConstants.INDETERMINATE);
1699         }
1700         if (Qfield == null) {
1701             return DatatypeConstants.INDETERMINATE;
1702         }
1703         return Pfield.compareTo(Qfield);
1704     }
1705 
1706     private static int compareField(BigDecimal Pfield, BigDecimal Qfield) {
1707         // optimization. especially when both arguments are null.
1708         if (Pfield == Qfield) {
1709             return DatatypeConstants.EQUAL;
1710         }
1711 
1712         if (Pfield == null) {
1713             Pfield = DECIMAL_ZERO;
1714         }
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;
1758         if (timezone != 0) {
1759             gc = this.normalizeToTimezone(getTimezone());
1760         }
1761         return gc.getYear() + gc.getMonth() + gc.getDay() +
1762                 gc.getHour() + gc.getMinute() + gc.getSecond();
1763     }
1764 
1765 
1766     /**
1767      * <p>Constructs a new XMLGregorianCalendar object by
1768      * parsing its lexical string representation as defined in
1769      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
1770      * <i>Lexical Representation</i>.</a></p>
1771      *
1772      * <p>The string representation may not have any leading and trailing whitespaces.</p>
1773      *
1774      * <p>The parsing is done field by field so that
1775      * the following holds for any lexically correct string x:</p>
1776      * <pre>
1777      * new XMLGregorianCalendar(x).toXMLFormat().equals(x)
1778      * </pre>
1779      * Except for the noted lexical/canonical representation mismatches
1780      * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
1781      * XML Schema 1.0 errata, Section 3.2.7.2</a>.
1782      *
1783      * <p>Returns a non-null valid XMLGregorianCalendar object that holds the value
1784      * indicated by the lexicalRepresentation parameter.</p>
1785      *
1786      * @param lexicalRepresentation Lexical representation of one the 8 XML Schema calendar datatypes.
1787      *
1788      * @return <code>XMLGregorianCalendar</code> created from parsing <code>lexicalRepresentation</code> parameter.
1789      *
1790      * @throws IllegalArgumentException
1791      *      If the given string does not conform to the aforementioned
1792      *      specification.
1793      * @throws NullPointerException
1794      *      If the given string is null.
1795      */
1796     public static XMLGregorianCalendar parse(String lexicalRepresentation) {
1797 
1798                 return new XMLGregorianCalendarImpl(lexicalRepresentation);
1799     }
1800 
1801     /**
1802      * <p>Return the lexical representation of <code>this</code> instance.
1803      * The format is specified in
1804      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
1805      * <i>Lexical Representation</i>".</a></p>
1806      *
1807      * <p>Specific target lexical representation format is determined by
1808      * {@link #getXMLSchemaType()}.</p>
1809      *
1810      * @return XML, as <code>String</code>, representation of this <code>XMLGregorianCalendar</code>
1811      *
1812      * @throws java.lang.IllegalStateException if the combination of set fields
1813      *    does not match one of the eight defined XML Schema builtin date/time datatypes.
1814      */
1815     public String toXMLFormat() {
1816 
1817         QName typekind = getXMLSchemaType();
1818 
1819         String formatString = null;
1820         // Fix 4971612: invalid SCCS macro substitution in data string
1821         //   no %{alpha}% to avoid SCCS macro substitution
1822         if (typekind == DatatypeConstants.DATETIME) {
1823             formatString = "%Y-%M-%DT%h:%m:%s" + "%z";
1824         } else if (typekind == DatatypeConstants.DATE) {
1825             formatString = "%Y-%M-%D" + "%z";
1826         } else if (typekind == DatatypeConstants.TIME) {
1827             formatString = "%h:%m:%s" + "%z";
1828         } else if (typekind == DatatypeConstants.GMONTH) {
1829             formatString = "--%M" + "%z";
1830         } else if (typekind == DatatypeConstants.GDAY) {
1831             formatString = "---%D" + "%z";
1832         } else if (typekind == DatatypeConstants.GYEAR) {
1833             formatString = "%Y" + "%z";
1834         } else if (typekind == DatatypeConstants.GYEARMONTH) {
1835             formatString = "%Y-%M" + "%z";
1836         } else if (typekind == DatatypeConstants.GMONTHDAY) {
1837             formatString = "--%M-%D" + "%z";
1838         }
1839         return format(formatString);
1840     }
1841 
1842     /**
1843      * <p>Return the name of the XML Schema date/time type that this instance
1844      * maps to. Type is computed based on fields that are set.</p>
1845      *
1846      * <table border="2" rules="all" cellpadding="2">
1847      *   <thead>
1848      *     <tr>
1849      *       <th align="center" colspan="7">
1850      *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
1851      *         <i>(timezone is optional for all date/time datatypes)</i>
1852      *       </th>
1853      *     </tr>
1854      *   </thead>
1855      *   <tbody>
1856      *     <tr>
1857      *       <td>Datatype</td>
1858      *       <td>year</td>
1859      *       <td>month</td>
1860      *       <td>day</td>
1861      *       <td>hour</td>
1862      *       <td>minute</td>
1863      *       <td>second</td>
1864      *     </tr>
1865      *     <tr>
1866      *       <td>{@link DatatypeConstants#DATETIME}</td>
1867      *       <td>X</td>
1868      *       <td>X</td>
1869      *       <td>X</td>
1870      *       <td>X</td>
1871      *       <td>X</td>
1872      *       <td>X</td>
1873      *     </tr>
1874      *     <tr>
1875      *       <td>{@link DatatypeConstants#DATE}</td>
1876      *       <td>X</td>
1877      *       <td>X</td>
1878      *       <td>X</td>
1879      *       <td></td>
1880      *       <td></td>
1881      *       <td></td>
1882      *     </tr>
1883      *     <tr>
1884      *       <td>{@link DatatypeConstants#TIME}</td>
1885      *       <td></td>
1886      *       <td></td>
1887      *       <td></td>
1888      *       <td>X</td>
1889      *       <td>X</td>
1890      *       <td>X</td>
1891      *     </tr>
1892      *     <tr>
1893      *       <td>{@link DatatypeConstants#GYEARMONTH}</td>
1894      *       <td>X</td>
1895      *       <td>X</td>
1896      *       <td></td>
1897      *       <td></td>
1898      *       <td></td>
1899      *       <td></td>
1900      *     </tr>
1901      *     <tr>
1902      *       <td>{@link DatatypeConstants#GMONTHDAY}</td>
1903      *       <td></td>
1904      *       <td>X</td>
1905      *       <td>X</td>
1906      *       <td></td>
1907      *       <td></td>
1908      *       <td></td>
1909      *     </tr>
1910      *     <tr>
1911      *       <td>{@link DatatypeConstants#GYEAR}</td>
1912      *       <td>X</td>
1913      *       <td></td>
1914      *       <td></td>
1915      *       <td></td>
1916      *       <td></td>
1917      *       <td></td>
1918      *     </tr>
1919      *     <tr>
1920      *       <td>{@link DatatypeConstants#GMONTH}</td>
1921      *       <td></td>
1922      *       <td>X</td>
1923      *       <td></td>
1924      *       <td></td>
1925      *       <td></td>
1926      *       <td></td>
1927      *     </tr>
1928      *     <tr>
1929      *       <td>{@link DatatypeConstants#GDAY}</td>
1930      *       <td></td>
1931      *       <td></td>
1932      *       <td>X</td>
1933      *       <td></td>
1934      *       <td></td>
1935      *       <td></td>
1936      *     </tr>
1937      *   </tbody>
1938      * </table>
1939      *
1940      * @throws java.lang.IllegalStateException if the combination of set fields
1941      *    does not match one of the eight defined XML Schema builtin
1942      *    date/time datatypes.
1943      * @return One of the following class constants:
1944      *   {@link DatatypeConstants#DATETIME},
1945      *   {@link DatatypeConstants#TIME},
1946      *   {@link DatatypeConstants#DATE},
1947      *   {@link DatatypeConstants#GYEARMONTH},
1948      *   {@link DatatypeConstants#GMONTHDAY},
1949      *   {@link DatatypeConstants#GYEAR},
1950      *   {@link DatatypeConstants#GMONTH} or
1951      *   {@link DatatypeConstants#GDAY}.
1952      */
1953     public QName getXMLSchemaType() {
1954 
1955         int mask =
1956             (year != DatatypeConstants.FIELD_UNDEFINED ?   0x20 : 0 )|
1957             (month != DatatypeConstants.FIELD_UNDEFINED ?  0x10 : 0 )|
1958             (day != DatatypeConstants.FIELD_UNDEFINED ?    0x08 : 0 )|
1959             (hour != DatatypeConstants.FIELD_UNDEFINED ?   0x04 : 0 )|
1960             (minute != DatatypeConstants.FIELD_UNDEFINED ? 0x02 : 0 )|
1961             (second != DatatypeConstants.FIELD_UNDEFINED ? 0x01 : 0 );
1962 
1963         switch(mask) {
1964         case 0x3F:
1965                 return DatatypeConstants.DATETIME;
1966         case 0x38:
1967                 return DatatypeConstants.DATE;
1968         case 0x07:
1969                 return DatatypeConstants.TIME;
1970         case 0x30:
1971                 return DatatypeConstants.GYEARMONTH;
1972         case 0x18:
1973                 return DatatypeConstants.GMONTHDAY;
1974         case 0x20:
1975                 return DatatypeConstants.GYEAR;
1976         case 0x10:
1977                 return DatatypeConstants.GMONTH;
1978         case 0x08:
1979                 return DatatypeConstants.GDAY;
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         /*
2051            * Extracted from
2052            * http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes
2053            * to ensure implemented properly. See spec for definitions of methods
2054            * used in algorithm.
2055            *
2056            * Given a dateTime S and a duration D, specifies how to compute a
2057            * dateTime E where E is the end of the time period with start S and
2058            * duration D i.e. E = S + D.
2059            *
2060            * The following is the precise specification.
2061            * These steps must be followed in the same order.
2062            * If a field in D is not specified, it is treated as if it were zero.
2063            * If a field in S is not specified, it is treated in the calculation
2064            * as if it were the minimum allowed value in that field, however,
2065            * after the calculation is concluded, the corresponding field in
2066            * E is removed (set to unspecified).
2067            *
2068            * Months (may be modified additionally below)
2069                *  temp := S[month] + D[month]
2070                *  E[month] := modulo(temp, 1, 13)
2071                *  carry := fQuotient(temp, 1, 13)
2072            */
2073 
2074         boolean fieldUndefined[] = {
2075                 false,
2076                 false,
2077                 false,
2078                 false,
2079                 false,
2080                 false
2081         };
2082 
2083         int signum = duration.getSign();
2084 
2085         int startMonth = getMonth();
2086         if (startMonth == DatatypeConstants.FIELD_UNDEFINED) {
2087             startMonth = DatatypeConstants.JANUARY;
2088             fieldUndefined[MONTH] = true;
2089         }
2090 
2091         BigInteger dMonths = sanitize(duration.getField(DatatypeConstants.MONTHS), signum);
2092         BigInteger temp = BigInteger.valueOf((long) startMonth).add(dMonths);
2093         setMonth(temp.subtract(BigInteger.ONE).mod(TWELVE).intValue() + 1);
2094         BigInteger carry =
2095                 new BigDecimal(temp.subtract(BigInteger.ONE)).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_FLOOR).toBigInteger();
2096 
2097         /* Years (may be modified additionally below)
2098             *  E[year] := S[year] + D[year] + carry
2099             */
2100         BigInteger startYear = getEonAndYear();
2101         if (startYear == null) {
2102             fieldUndefined[YEAR] = true;
2103             startYear = BigInteger.ZERO;
2104         }
2105         BigInteger dYears = sanitize(duration.getField(DatatypeConstants.YEARS), signum);
2106         BigInteger endYear = startYear.add(dYears).add(carry);
2107         setYear(endYear);
2108 
2109         /* Zone
2110                *  E[zone] := S[zone]
2111            *
2112            * no-op since adding to this, not to a new end point.
2113            */
2114 
2115         /* Seconds
2116             *  temp := S[second] + D[second]
2117             *  E[second] := modulo(temp, 60)
2118             *  carry := fQuotient(temp, 60)
2119             */
2120         BigDecimal startSeconds;
2121         if (getSecond() == DatatypeConstants.FIELD_UNDEFINED) {
2122             fieldUndefined[SECOND] = true;
2123             startSeconds = DECIMAL_ZERO;
2124         } else {
2125             // seconds + fractionalSeconds
2126             startSeconds = getSeconds();
2127         }
2128 
2129         // Duration seconds is SECONDS + FRACTIONALSECONDS.
2130         BigDecimal dSeconds = DurationImpl.sanitize((BigDecimal) duration.getField(DatatypeConstants.SECONDS), signum);
2131         BigDecimal tempBD = startSeconds.add(dSeconds);
2132         BigDecimal fQuotient =
2133                 new BigDecimal(new BigDecimal(tempBD.toBigInteger()).divide(DECIMAL_SIXTY, BigDecimal.ROUND_FLOOR).toBigInteger());
2134         BigDecimal endSeconds = tempBD.subtract(fQuotient.multiply(DECIMAL_SIXTY));
2135 
2136         carry = fQuotient.toBigInteger();
2137         setSecond(endSeconds.intValue());
2138         BigDecimal tempFracSeconds = endSeconds.subtract(new BigDecimal(BigInteger.valueOf((long) getSecond())));
2139         if (tempFracSeconds.compareTo(DECIMAL_ZERO) < 0) {
2140             setFractionalSecond(DECIMAL_ONE.add(tempFracSeconds));
2141             if (getSecond() == 0) {
2142                 setSecond(59);
2143                 carry = carry.subtract(BigInteger.ONE);
2144             } else {
2145                 setSecond(getSecond() - 1);
2146             }
2147         } else {
2148             setFractionalSecond(tempFracSeconds);
2149         }
2150 
2151         /* Minutes
2152                *  temp := S[minute] + D[minute] + carry
2153                *  E[minute] := modulo(temp, 60)
2154                *  carry := fQuotient(temp, 60)
2155            */
2156         int startMinutes = getMinute();
2157         if (startMinutes == DatatypeConstants.FIELD_UNDEFINED) {
2158             fieldUndefined[MINUTE] = true;
2159             startMinutes = 0;
2160         }
2161         BigInteger dMinutes = sanitize(duration.getField(DatatypeConstants.MINUTES), signum);
2162 
2163         temp = BigInteger.valueOf(startMinutes).add(dMinutes).add(carry);
2164         setMinute(temp.mod(SIXTY).intValue());
2165         carry = new BigDecimal(temp).divide(DECIMAL_SIXTY, BigDecimal.ROUND_FLOOR).toBigInteger();
2166 
2167         /* Hours
2168                *  temp := S[hour] + D[hour] + carry
2169                *  E[hour] := modulo(temp, 24)
2170                *  carry := fQuotient(temp, 24)
2171            */
2172         int startHours = getHour();
2173         if (startHours == DatatypeConstants.FIELD_UNDEFINED) {
2174             fieldUndefined[HOUR] = true;
2175             startHours = 0;
2176         }
2177         BigInteger dHours = sanitize(duration.getField(DatatypeConstants.HOURS), signum);
2178 
2179         temp = BigInteger.valueOf(startHours).add(dHours).add(carry);
2180         setHour(temp.mod(TWENTY_FOUR).intValue(), false);
2181         carry = new BigDecimal(temp).divide(new BigDecimal(TWENTY_FOUR), BigDecimal.ROUND_FLOOR).toBigInteger();
2182 
2183         /* Days
2184            *  if S[day] > maximumDayInMonthFor(E[year], E[month])
2185            *       + tempDays := maximumDayInMonthFor(E[year], E[month])
2186            *  else if S[day] < 1
2187            *       + tempDays := 1
2188            *  else
2189            *       + tempDays := S[day]
2190            *  E[day] := tempDays + D[day] + carry
2191            *  START LOOP
2192            *       + IF E[day] < 1
2193            *             # E[day] := E[day] +
2194             *                 maximumDayInMonthFor(E[year], E[month] - 1)
2195            *             # carry := -1
2196            *       + ELSE IF E[day] > maximumDayInMonthFor(E[year], E[month])
2197            *             # E[day] :=
2198             *                    E[day] - maximumDayInMonthFor(E[year], E[month])
2199            *             # carry := 1
2200            *       + ELSE EXIT LOOP
2201            *       + temp := E[month] + carry
2202            *       + E[month] := modulo(temp, 1, 13)
2203            *       + E[year] := E[year] + fQuotient(temp, 1, 13)
2204            *       + GOTO START LOOP
2205            */
2206         BigInteger tempDays;
2207         int startDay = getDay();
2208         if (startDay == DatatypeConstants.FIELD_UNDEFINED) {
2209             fieldUndefined[DAY] = true;
2210             startDay = 1;
2211         }
2212         BigInteger dDays = sanitize(duration.getField(DatatypeConstants.DAYS), signum);
2213         int maxDayInMonth = maximumDayInMonthFor(getEonAndYear(), getMonth());
2214         if (startDay > maxDayInMonth) {
2215             tempDays = BigInteger.valueOf(maxDayInMonth);
2216         } else if (startDay < 1) {
2217             tempDays = BigInteger.ONE;
2218         } else {
2219             tempDays = BigInteger.valueOf(startDay);
2220         }
2221         BigInteger endDays = tempDays.add(dDays).add(carry);
2222         int monthCarry;
2223         int intTemp;
2224         while (true) {
2225             if (endDays.compareTo(BigInteger.ONE) < 0) {
2226                 // calculate days in previous month, watch for month roll over
2227                 BigInteger mdimf = null;
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);
2269                     break;
2270                 case DAY:
2271                     setDay(DatatypeConstants.FIELD_UNDEFINED);
2272                     break;
2273                 case HOUR:
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>
2350      *     <tr>
2351      *       <th align="center" colspan="2">
2352      *          Field by Field Conversion from this class to
2353      *          <code>java.util.GregorianCalendar</code>
2354      *       </th>
2355      *     </tr>
2356      *   </thead>
2357      *   <tbody>
2358      *     <tr>
2359      *        <th><code>java.util.GregorianCalendar</code> field</th>
2360      *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
2361      *     </tr>
2362      *     <tr>
2363      *       <th><code>ERA</code></th>
2364      *       <th>{@link #getEonAndYear()}<code>.signum() < 0 ? GregorianCalendar.BC : GregorianCalendar.AD</code></th>
2365      *     </tr>
2366      *     <tr>
2367      *       <th><code>YEAR</code></th>
2368      *       <th>{@link #getEonAndYear()}<code>.abs().intValue()</code><i>*</i></th>
2369      *     </tr>
2370      *     <tr>
2371      *       <th><code>MONTH</code></th>
2372      *       <th>{@link #getMonth()}<code> - 1</code></th>
2373      *     </tr>
2374      *     <tr>
2375      *       <th><code>DAY_OF_MONTH</code></th>
2376      *       <th>{@link #getDay()}</th>
2377      *     </tr>
2378      *     <tr>
2379      *       <th><code>AM_PM</code></th>
2380      *       <th>{@link #getHour()} < 12 : Calendar.AM : Calendar.PM</th>
2381      *     </tr>
2382      *     <tr>
2383      *       <th><code>HOUR_OF_DAY</code></th>
2384      *       <th>{@link #getHour()}</th>
2385      *     </tr>
2386      *     <tr>
2387      *       <th><code>MINUTE</code></th>
2388      *       <th>{@link #getMinute()}</th>
2389      *     </tr>
2390      *     <tr>
2391      *       <th><code>SECOND</code></th>
2392      *       <th>{@link #getSecond()}</th>
2393      *     </tr>
2394      *     <tr>
2395      *       <th><code>MILLISECOND</code></th>
2396      *       <th>get millisecond order from {@link #getFractionalSecond()}<i>*</i> </th>
2397      *     </tr>
2398      *     <tr>
2399      *       <th><code>GregorianCalendar.setTimeZone(TimeZone)</code></th>
2400      *       <th>{@link #getTimezone()} formatted into Custom timezone id</th>
2401      *     </tr>
2402      *   </tbody>
2403      * </table>
2404      * <i>*</i> designates possible loss of precision during the conversion due
2405      * to source datatype having higer precison than target datatype.
2406      *
2407      * <p>To ensure consistency in conversion implementations, the new
2408      * <code>GregorianCalendar</code> should be instantiated in following
2409      * manner.
2410      * <ul>
2411      *   <li>Using <code>timeZone</code> value as defined above, create a new
2412      * <code>java.util.GregorianCalendar(timeZone,Locale.getDefault())</code>.
2413      *   </li>
2414      *   <li>Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.</li>
2415      *   <li>Obtain a pure Gregorian Calendar by invoking
2416      *   <code>GregorianCalendar.setGregorianChange(
2417      *   new Date(Long.MIN_VALUE))</code>.</li>
2418      *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
2419      *       MINUTE, SECOND and MILLISECOND are set using the method
2420      *       <code>Calendar.set(int,int)</code></li>
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);
2472         }
2473 
2474         // only set second if it is set
2475         if (second != DatatypeConstants.FIELD_UNDEFINED) {
2476             result.set(Calendar.SECOND, second);
2477         }
2478 
2479         // only set millisend if it is set
2480         if (fractionalSecond != null) {
2481             result.set(Calendar.MILLISECOND, getMillisecond());
2482         }
2483 
2484         return result;
2485     }
2486 
2487     /**
2488      *
2489      * @return default locale
2490      */
2491     private Locale getDefaultLocale() {
2492 
2493         String lang = SecuritySupport.getSystemProperty("user.language.format");
2494         String country = SecuritySupport.getSystemProperty("user.country.format");
2495         String variant = SecuritySupport.getSystemProperty("user.variant.format");
2496         Locale locale = null;
2497         if (lang != null) {
2498             if (country != null) {
2499                 if (variant != null) {
2500                     locale = new Locale(lang, country, variant);
2501                 } else {
2502                     locale = new Locale(lang, country);
2503                 }
2504             } else {
2505                 locale = new Locale(lang);
2506             }
2507         }
2508         if (locale == null) {
2509             locale = Locale.getDefault();
2510         }
2511         return locale;
2512     }
2513 
2514     /**
2515      * <p>Convert <code>this</code> along with provided parameters
2516      * to <code>java.util.GregorianCalendar</code> instance.</p>
2517      *
2518      * <p> Since XML Schema 1.0 date/time datetypes has no concept of
2519      * timezone ids or daylight savings timezone ids, this conversion operation
2520      * allows the user to explicitly specify one with
2521      * <code>timezone</code> parameter.</p>
2522      *
2523      * <p>To compute the return value's <code>TimeZone</code> field,
2524      * <ul>
2525      * <li>when parameter <code>timeZone</code> is non-null,
2526      * it is the timezone field.</li>
2527      * <li>else when <code>this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
2528      * create a <code>java.util.TimeZone</code> with a custom timezone id
2529      * using the <code>this.getTimezone()</code>.</li>
2530      * <li>else when <code>defaults.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
2531      * create a <code>java.util.TimeZone</code> with a custom timezone id
2532      * using <code>defaults.getTimezone()</code>.</li>
2533      * <li>else use the <code>GregorianCalendar</code> default timezone value
2534      * for the host is definedas specified by
2535      * <code>java.util.TimeZone.getDefault()</code>.</li></p>
2536      *
2537      * <p>To ensure consistency in conversion implementations, the new
2538      * <code>GregorianCalendar</code> should be instantiated in following
2539      * manner.
2540      * <ul>
2541      *   <li>Create a new <code>java.util.GregorianCalendar(TimeZone,
2542      *       Locale)</code> with TimeZone set as specified above and the
2543      *       <code>Locale</code> parameter.
2544      *   </li>
2545      *   <li>Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.</li>
2546      *   <li>Obtain a pure Gregorian Calendar by invoking
2547      *   <code>GregorianCalendar.setGregorianChange(
2548      *   new Date(Long.MIN_VALUE))</code>.</li>
2549      *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
2550      *       MINUTE, SECOND and MILLISECOND are set using the method
2551      *       <code>Calendar.set(int,int)</code></li>
2552      * </ul>
2553      *
2554      * @param timezone provide Timezone. <code>null</code> is a legal value.
2555      * @param aLocale  provide explicit Locale. Use default GregorianCalendar locale if
2556      *                 value is <code>null</code>.
2557      * @param defaults provide default field values to use when corresponding
2558      *                 field for this instance is DatatypeConstants.FIELD_UNDEFINED or null.
2559      *                 If <code>defaults</code>is <code>null</code> or a field
2560      *                 within the specified <code>defaults</code> is undefined,
2561      *                 just use <code>java.util.GregorianCalendar</code> defaults.
2562      * @return a java.util.GregorianCalendar conversion of this instance.
2563      *
2564      * @see #LEAP_YEAR_DEFAULT
2565      */
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
2697      * {@link DatatypeConstants#FIELD_UNDEFINED}.
2698      *
2699      * @return TimeZone for this.
2700      */
2701     public TimeZone getTimeZone(int defaultZoneoffset) {
2702         TimeZone result = null;
2703         int zoneoffset = getTimezone();
2704 
2705         if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) {
2706             zoneoffset = defaultZoneoffset;
2707         }
2708         if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) {
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);
2752     }
2753 
2754     /**
2755      * <p>Unset all fields to undefined.</p>
2756      *
2757      * <p>Set all int fields to {@link DatatypeConstants#FIELD_UNDEFINED} and reference fields
2758      * to null.</p>
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;
2800 
2801         private int fidx;
2802         private int vidx;
2803 
2804         private Parser(String format, String value) {
2805             this.format = format;
2806             this.value = value;
2807             this.flen = format.length();
2808             this.vlen = value.length();
2809         }
2810 
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));
2852 
2853                         if (peek() == '.') {
2854                             setFractionalSecond(parseBigDecimal());
2855                         }
2856                         break;
2857 
2858                     case 'z' : // time zone. missing, 'Z', or [+-]nn:nn
2859                         char vch = peek();
2860                         if (vch == 'Z') {
2861                             vidx++;
2862                             setTimezone(0);
2863                         } else if (vch == '+' || vch == '-') {
2864                             vidx++;
2865                             int h = parseInt(2, 2);
2866                             skip(':');
2867                             int m = parseInt(2, 2);
2868                             setTimezone((h * 60 + m) * (vch == '+' ? 1 : -1));
2869                         }
2870 
2871                         break;
2872 
2873                     default :
2874                         // illegal meta character. impossible.
2875                         throw new InternalError();
2876                 }
2877             }
2878 
2879             if (vidx != vlen) {
2880                 // some tokens are left in the input
2881                 throw new IllegalArgumentException(value); //,vidx);
2882             }
2883             testHour();
2884         }
2885 
2886         private char peek() throws IllegalArgumentException {
2887             if (vidx == vlen) {
2888                 return (char) -1;
2889             }
2890             return value.charAt(vidx);
2891         }
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 }