1/*
2 * Copyright (c) 2004, 2017, 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
26package com.sun.org.apache.xerces.internal.jaxp.datatype;
27
28import com.sun.org.apache.xerces.internal.util.DatatypeMessageFormatter;
29import com.sun.org.apache.xerces.internal.utils.SecuritySupport;
30import java.io.IOException;
31import java.io.ObjectInputStream;
32import java.io.Serializable;
33import java.math.BigDecimal;
34import java.math.BigInteger;
35import java.math.RoundingMode;
36import java.util.Calendar;
37import java.util.Date;
38import java.util.GregorianCalendar;
39import java.util.Locale;
40import java.util.TimeZone;
41import javax.xml.datatype.DatatypeConstants;
42import javax.xml.datatype.Duration;
43import javax.xml.datatype.XMLGregorianCalendar;
44import javax.xml.namespace.QName;
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 * @see javax.xml.datatype.Duration
192 * @since 1.5
193 */
194
195public class XMLGregorianCalendarImpl
196        extends XMLGregorianCalendar
197        implements Serializable, Cloneable {
198
199    /** Backup values **/
200    transient private BigInteger orig_eon;
201    transient private int orig_year = DatatypeConstants.FIELD_UNDEFINED;
202    transient private int orig_month = DatatypeConstants.FIELD_UNDEFINED;
203    transient private int orig_day = DatatypeConstants.FIELD_UNDEFINED;
204    transient private int orig_hour = DatatypeConstants.FIELD_UNDEFINED;
205    transient private int orig_minute = DatatypeConstants.FIELD_UNDEFINED;
206    transient private int orig_second = DatatypeConstants.FIELD_UNDEFINED;
207    transient private BigDecimal orig_fracSeconds;
208    transient private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED;
209
210    /**
211     * <p>Eon of this <code>XMLGregorianCalendar</code>.</p>
212     */
213    private BigInteger eon = null;
214
215    /**
216     * <p>Year of this <code>XMLGregorianCalendar</code>.</p>
217     */
218    private int year = DatatypeConstants.FIELD_UNDEFINED;
219
220    /**
221     * <p>Month of this <code>XMLGregorianCalendar</code>.</p>
222     */
223    private int month = DatatypeConstants.FIELD_UNDEFINED;
224
225    /**
226     * <p>Day of this <code>XMLGregorianCalendar</code>.</p>
227     */
228    private int day = DatatypeConstants.FIELD_UNDEFINED;
229
230    /**
231     * <p>Timezone of this <code>XMLGregorianCalendar</code> in minutes.</p>
232     */
233    private int timezone = DatatypeConstants.FIELD_UNDEFINED;
234
235    /**
236     * <p>Hour of this <code>XMLGregorianCalendar</code>.</p>
237     */
238    private int hour = DatatypeConstants.FIELD_UNDEFINED;
239
240    /**
241     * <p>Minute of this <code>XMLGregorianCalendar</code>.</p>
242     */
243    private int minute = DatatypeConstants.FIELD_UNDEFINED;
244
245    /**
246     * <p>Second of this <code>XMLGregorianCalendar</code>.</p>
247     */
248    private int second = DatatypeConstants.FIELD_UNDEFINED ;
249
250    /**
251     * <p>Fractional second of this <code>XMLGregorianCalendar</code>.</p>
252     */
253    private BigDecimal fractionalSecond = null;
254
255    /**
256     * <p>BigInteger constant; representing a billion.</p>
257     */
258    private static final BigInteger BILLION_B = new BigInteger("1000000000");
259
260    /**
261     * <p>int constant; representing a billion.</p>
262     */
263    private static final int BILLION_I = 1000000000;
264
265    /**
266     *   <p>Obtain a pure Gregorian Calendar by calling
267     *   GregorianCalendar.setChange(PURE_GREGORIAN_CHANGE). </p>
268     */
269    private static final Date PURE_GREGORIAN_CHANGE =
270        new Date(Long.MIN_VALUE);
271
272    /**
273     * Year index for MIN_ and MAX_FIELD_VALUES.
274     */
275    private static final int YEAR   = 0;
276
277    /**
278     * Month index for MIN_ and MAX_FIELD_VALUES.
279     */
280    private static final int MONTH  = 1;
281
282    /**
283     * Day index for MIN_ and MAX_FIELD_VALUES.
284     */
285    private static final int DAY    = 2;
286
287    /**
288     * Hour index for MIN_ and MAX_FIELD_VALUES.
289     */
290    private static final int HOUR   = 3;
291
292    /**
293     * Minute index for MIN_ and MAX_FIELD_VALUES.
294     */
295    private static final int MINUTE = 4;
296
297    /**
298     * Second index for MIN_ and MAX_FIELD_VALUES.
299     */
300    private static final int SECOND = 5;
301
302    /**
303     * Second index for MIN_ and MAX_FIELD_VALUES.
304     */
305    private static final int MILLISECOND = 6;
306
307    /**
308     * Timezone index for MIN_ and MAX_FIELD_VALUES
309     */
310    private static final int TIMEZONE = 7;
311
312
313    /**
314     * field names indexed by YEAR..TIMEZONE.
315     */
316    private static final String FIELD_NAME[] = {
317        "Year",
318        "Month",
319        "Day",
320        "Hour",
321        "Minute",
322        "Second",
323        "Millisecond",
324        "Timezone"
325    };
326
327    /**
328     * <p>Stream Unique Identifier.</p>
329     *
330     * <p>TODO: Serialization should use the XML string representation as
331     * the serialization format to ensure future compatibility.</p>
332     */
333    private static final long serialVersionUID = 1L;
334
335    /**
336     * <p>Use as a template for default field values when
337     * converting to a {@link GregorianCalendar}, set to a leap
338     * year date of January 1, 0400 at midnight.</p>
339     *
340     * <p>Fields that are optional for an <code>xsd:dateTime</code> instances are defaulted to not being set to any value.
341     * <code>XMLGregorianCalendar</code> fields millisecond, fractional second and timezone return the value indicating
342     * that the field is not set, {@link DatatypeConstants#FIELD_UNDEFINED} for millisecond and timezone
343     * and <code>null</code> for fractional second.</p>
344     *
345     * @see #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)
346     */
347    public static final XMLGregorianCalendar LEAP_YEAR_DEFAULT =
348                createDateTime(
349                        400,  //year
350                DatatypeConstants.JANUARY,  //month
351                        1,  // day
352                    0,  // hour
353                    0,  // minute
354                    0,  // second
355                    DatatypeConstants.FIELD_UNDEFINED,  // milliseconds
356                    DatatypeConstants.FIELD_UNDEFINED // timezone
357                );
358
359    // Constructors
360
361    /**
362     * Constructs a new XMLGregorianCalendar object.
363     *
364     * String parsing documented by {@link #parse(String)}.
365     *
366     * Returns a non-null valid XMLGregorianCalendar object that holds the
367     * value indicated by the lexicalRepresentation parameter.
368     *
369     * @param lexicalRepresentation
370     *      Lexical representation of one the eight
371     *      XML Schema date/time datatypes.
372     * @throws IllegalArgumentException
373     *      If the given string does not conform as documented in
374     *      {@link #parse(String)}.
375     * @throws NullPointerException
376     *      If the given string is null.
377     */
378    protected XMLGregorianCalendarImpl(String lexicalRepresentation)
379            throws IllegalArgumentException {
380
381        // compute format string for this lexical representation.
382        String format;
383        String lexRep = lexicalRepresentation;
384        final int NOT_FOUND = -1;
385        int lexRepLength = lexRep.length();
386
387        // current parser needs a format string,
388        // use following heuristics to figure out what xml schema date/time
389        // datatype this lexical string could represent.
390        // Fix 4971612: invalid SCCS macro substitution in data string,
391        //   no %{alpha}% to avoid SCCS maco substitution
392        if (lexRep.indexOf('T') != NOT_FOUND) {
393            // found Date Time separater, must be xsd:DateTime
394            format = "%Y-%M-%DT%h:%m:%s" + "%z";
395        } else if (lexRepLength >= 3 && lexRep.charAt(2) == ':') {
396            // found ":", must be xsd:Time
397            format = "%h:%m:%s" + "%z";
398        } else if (lexRep.startsWith("--")) {
399            // check for gDay || gMonth || gMonthDay
400            if (lexRepLength >= 3 && lexRep.charAt(2) == '-') {
401                // gDay, ---DD(z?)
402                format = "---%D" + "%z";
403            } else if (lexRepLength == 4     // --MM
404                    || lexRepLength == 5     // --MMZ
405                    || lexRepLength == 10) { // --MMSHH:MM
406                // gMonth, --MM(z?),
407                // per XML Schema Errata, used to be --MM--(z?)
408                format = "--%M" + "%z";
409            } else {
410                // gMonthDay, --MM-DD(z?), (or invalid lexicalRepresentation)
411                // length should be:
412                //  7: --MM-DD
413                //  8: --MM-DDZ
414                // 13: --MM-DDSHH:MM
415                format = "--%M-%D" + "%z";
416            }
417        } else {
418            // check for Date || GYear | GYearMonth
419            int countSeparator = 0;
420
421            // start at index 1 to skip potential negative sign for year.
422
423
424            int timezoneOffset = lexRep.indexOf(':');
425            if (timezoneOffset != NOT_FOUND) {
426
427                // found timezone, strip it off for distinguishing
428                // between Date, GYear and GYearMonth so possible
429                // negative sign in timezone is not mistaken as
430                // a separator.
431                lexRepLength -= 6;
432            }
433
434            for (int i = 1; i < lexRepLength; i++) {
435                if (lexRep.charAt(i) == '-') {
436                    countSeparator++;
437                }
438            }
439            if (countSeparator == 0) {
440                // GYear
441                format = "%Y" + "%z";
442            } else if (countSeparator == 1) {
443                // GYearMonth
444                format = "%Y-%M" + "%z";
445            } else {
446                // Date or invalid lexicalRepresentation
447                // Fix 4971612: invalid SCCS macro substitution in data string
448                format = "%Y-%M-%D" + "%z";
449            }
450        }
451        Parser p = new Parser(format, lexRep);
452        p.parse();
453
454        // check for validity
455        if (!isValid()) {
456            throw new IllegalArgumentException(
457                    DatatypeMessageFormatter.formatMessage(null, "InvalidXGCRepresentation", new Object[]{lexicalRepresentation})
458                    //"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value."
459            );
460        }
461
462        save();
463    }
464
465    /**
466     * save original values
467     */
468    private void save() {
469        orig_eon = eon;
470        orig_year = year;
471        orig_month = month;
472        orig_day = day;
473        orig_hour = hour;
474        orig_minute = minute;
475        orig_second = second;
476        orig_fracSeconds = fractionalSecond;
477        orig_timezone = timezone;
478    }
479
480    /**
481     * <p>Create an instance with all date/time datatype fields set to
482     * {@link DatatypeConstants#FIELD_UNDEFINED} or null respectively.</p>
483     */
484    public XMLGregorianCalendarImpl() {
485
486        // field initializers already do the correct initialization.
487    }
488
489    /**
490     * <p>Private constructor allowing for complete value spaces allowed by
491     * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
492     * builtin datatypes. Note that <code>year</code> parameter supports
493     * arbitrarily large numbers and fractionalSecond has infinite
494     * precision.</p>
495     *
496     * @param year of <code>XMLGregorianCalendar</code> to be created.
497     * @param month of <code>XMLGregorianCalendar</code> to be created.
498     * @param day of <code>XMLGregorianCalendar</code> to be created.
499     * @param hour of <code>XMLGregorianCalendar</code> to be created.
500     * @param minute of <code>XMLGregorianCalendar</code> to be created.
501     * @param second of <code>XMLGregorianCalendar</code> to be created.
502     * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
503     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
504     *
505     */
506    protected XMLGregorianCalendarImpl(
507        BigInteger year,
508        int month,
509        int day,
510        int hour,
511        int minute,
512        int second,
513        BigDecimal fractionalSecond,
514        int timezone) {
515
516        setYear(year);
517        setMonth(month);
518        setDay(day);
519        setTime(hour, minute, second, fractionalSecond);
520        setTimezone(timezone);
521
522        // check for validity
523        if (!isValid()) {
524
525            throw new IllegalArgumentException(
526                DatatypeMessageFormatter.formatMessage(null,
527                    "InvalidXGCValue-fractional",
528                    new Object[] { year, month, day,
529                    hour, minute, second,
530                    fractionalSecond, timezone})
531                        );
532        }
533
534        save();
535    }
536
537    /**
538     * <p>Private constructor of value spaces that a
539     * <code>java.util.GregorianCalendar</code> instance would need to convert to an
540     * <code>XMLGregorianCalendar</code> instance.</p>
541     *
542     * <p><code>XMLGregorianCalendar eon</code> and
543     * <code>fractionalSecond</code> are set to <code>null</code></p>
544     *
545     * @param year of <code>XMLGregorianCalendar</code> to be created.
546     * @param month of <code>XMLGregorianCalendar</code> to be created.
547     * @param day of <code>XMLGregorianCalendar</code> to be created.
548     * @param hour of <code>XMLGregorianCalendar</code> to be created.
549     * @param minute of <code>XMLGregorianCalendar</code> to be created.
550     * @param second of <code>XMLGregorianCalendar</code> to be created.
551     * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
552     * @param timezone of <code>XMLGregorianCalendar</code> to be created.
553     */
554    private XMLGregorianCalendarImpl(
555        int year,
556        int month,
557        int day,
558        int hour,
559        int minute,
560        int second,
561        int millisecond,
562        int timezone) {
563
564        setYear(year);
565        setMonth(month);
566        setDay(day);
567        setTime(hour, minute, second);
568        setTimezone(timezone);
569        BigDecimal realMilliseconds = null;
570        if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
571            realMilliseconds = BigDecimal.valueOf(millisecond, 3);
572        }
573        setFractionalSecond(realMilliseconds);
574
575        if (!isValid()) {
576
577            throw new IllegalArgumentException(
578                DatatypeMessageFormatter.formatMessage(null,
579                "InvalidXGCValue-milli",
580                new Object[] { year, month, day,
581                hour, minute, second,
582                millisecond, timezone})
583                        );
584        }
585
586        save();
587    }
588
589        /**
590         * <p>Convert a <code>java.util.GregorianCalendar</code> to XML Schema 1.0
591         * representation.</p>
592         *
593         * <table border="2" rules="all" cellpadding="2">
594         *   <thead>
595         *     <tr>
596         *       <th align="center" colspan="2">
597         *          Field by Field Conversion from
598         *          <code>java.util.GregorianCalendar</code> to this class
599         *       </th>
600         *     </tr>
601         *   </thead>
602         *   <tbody>
603         *     <tr>
604         *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
605         *        <th><code>java.util.GregorianCalendar</code> field</th>
606         *     </tr>
607         *     <tr>
608         *       <th>{@link #setYear(int)}</th>
609         *       <th><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></th>
610         *     </tr>
611         *     <tr>
612         *       <th>{@link #setMonth(int)}</th>
613         *       <th><code>MONTH + 1</code></th>
614         *     </tr>
615         *     <tr>
616         *       <th>{@link #setDay(int)}</th>
617         *       <th><code>DAY_OF_MONTH</code></th>
618         *     </tr>
619         *     <tr>
620         *       <th>{@link #setTime(int,int,int, BigDecimal)}</th>
621         *       <th><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></th>
622         *     </tr>
623         *     <tr>
624         *       <th>{@link #setTimezone(int)}<i>*</i></th>
625         *       <th><code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
626         *       <i>(in minutes)</i>
627         *       </th>
628         *     </tr>
629         *   </tbody>
630         * </table>
631         * <p><i>*</i>conversion loss of information. It is not possible to represent
632         * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
633         * XML Schema 1.0 date/time datatype representation.</p>
634         *
635         * <p>To compute the return value's <code>TimeZone</code> field,
636         * <ul>
637         * <li>when <code>this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
638         * create a <code>java.util.TimeZone</code> with a custom timezone id
639         * using the <code>this.getTimezone()</code>.</li>
640         * <li>else use the <code>GregorianCalendar</code> default timezone value
641         * for the host is defined as specified by
642         * <code>java.util.TimeZone.getDefault()</code>.</li></p>
643         *
644         * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
645         */
646    public XMLGregorianCalendarImpl(GregorianCalendar cal) {
647
648        int year1 = cal.get(Calendar.YEAR);
649        if (cal.get(Calendar.ERA) == GregorianCalendar.BC) {
650            year1 = -year1;
651        }
652        this.setYear(year1);
653
654        // Calendar.MONTH is zero based, XSD Date datatype's month field starts
655        // with JANUARY as 1.
656        this.setMonth(cal.get(Calendar.MONTH) + 1);
657        this.setDay(cal.get(Calendar.DAY_OF_MONTH));
658        this.setTime(
659                cal.get(Calendar.HOUR_OF_DAY),
660                cal.get(Calendar.MINUTE),
661                cal.get(Calendar.SECOND),
662                cal.get(Calendar.MILLISECOND));
663
664        // Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds.
665        int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
666        this.setTimezone(offsetInMinutes);
667        save();
668    }
669
670    // Factories
671
672    /**
673     * <p>Create a Java representation of XML Schema builtin datatype <code>dateTime</code>.
674     * All possible fields are specified for this factory method.</p>
675     *
676     * @param year represents both high-order eons and low-order year.
677     * @param month of <code>dateTime</code>
678     * @param day of <code>dateTime</code>
679     * @param hours of <code>dateTime</code>
680     * @param minutes of <code>dateTime</code>
681     * @param seconds of <code>dateTime</code>
682     * @param fractionalSecond value of null indicates optional field is absent.
683     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
684     *
685     * @return <code>XMLGregorianCalendar</code> created from parameter values.
686     *
687     * @see DatatypeConstants#FIELD_UNDEFINED
688     *
689     * @throws IllegalArgumentException if any parameter is outside value
690     * constraints for the field as specified in
691     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
692     */
693    public static XMLGregorianCalendar createDateTime(
694        BigInteger year,
695        int month,
696        int day,
697        int hours,
698        int minutes,
699        int seconds,
700        BigDecimal fractionalSecond,
701        int timezone) {
702
703        return new XMLGregorianCalendarImpl(
704            year,
705            month,
706            day,
707            hours,
708            minutes,
709            seconds,
710            fractionalSecond,
711            timezone);
712    }
713
714    /**
715     * <p>Create a Java instance of XML Schema builtin datatype dateTime.</p>
716     *
717     * @param year represents both high-order eons and low-order year.
718     * @param month of <code>dateTime</code>
719     * @param day of <code>dateTime</code>
720     * @param hour of <code>dateTime</code>
721     * @param minute of <code>dateTime</code>
722     * @param second of <code>dateTime</code>
723     *
724     * @return <code>XMLGregorianCalendar</code> created from parameter values.
725     *
726     * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in
727     *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
728     *
729     * @see DatatypeConstants#FIELD_UNDEFINED
730     */
731    public static XMLGregorianCalendar createDateTime(
732        int year,
733        int month,
734        int day,
735        int hour,
736        int minute,
737        int second) {
738
739        return new XMLGregorianCalendarImpl(
740            year,
741            month,
742            day,
743            hour,
744            minute,
745            second,
746            DatatypeConstants.FIELD_UNDEFINED,  //millisecond
747                DatatypeConstants.FIELD_UNDEFINED //timezone
748        );
749    }
750
751    /**
752     * <p>Create a Java representation of XML Schema builtin datatype <code>dateTime</code>.
753     * All possible fields are specified for this factory method.</p>
754     *
755     * @param year represents low-order year.
756     * @param month of <code>dateTime</code>
757     * @param day of <code>dateTime</code>
758     * @param hours of <code>dateTime</code>
759     * @param minutes of <code>dateTime</code>
760     * @param seconds of <code>dateTime</code>
761     * @param milliseconds of <code>dateTime</code>. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
762     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
763     *
764     * @return <code>XMLGregorianCalendar</code> created from parameter values.
765     *
766     * @throws IllegalArgumentException if any parameter is outside value constraints for the field as specified in
767     *   <a href="#datetimefieldmapping">date/time field mapping table</a>.
768     *
769     * @see DatatypeConstants#FIELD_UNDEFINED
770     */
771    public static XMLGregorianCalendar createDateTime(
772        int year,
773        int month,
774        int day,
775        int hours,
776        int minutes,
777        int seconds,
778        int milliseconds,
779        int timezone) {
780
781        return new XMLGregorianCalendarImpl(
782            year,
783            month,
784            day,
785            hours,
786            minutes,
787            seconds,
788            milliseconds,
789            timezone);
790    }
791
792    /**
793     * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
794     *
795     * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
796     * with <code>month</code> and <code>day</code> parameters set to
797     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
798     *
799     * @param year of <code>XMLGregorianCalendar</code> to be created.
800     * @param month of <code>XMLGregorianCalendar</code> to be created.
801     * @param day of <code>XMLGregorianCalendar</code> to be created.
802     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
803     *
804     * @return <code>XMLGregorianCalendar</code> created from parameter values.
805     *
806     * @see DatatypeConstants#FIELD_UNDEFINED
807     *
808     * @throws IllegalArgumentException if any parameter is outside value
809     * constraints for the field as specified in
810     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
811     */
812    public static XMLGregorianCalendar createDate(
813        int year,
814        int month,
815        int day,
816        int timezone) {
817
818        return new XMLGregorianCalendarImpl(
819            year,
820            month,
821            day,
822            DatatypeConstants.FIELD_UNDEFINED, // hour
823            DatatypeConstants.FIELD_UNDEFINED, // minute
824            DatatypeConstants.FIELD_UNDEFINED, // second
825                DatatypeConstants.FIELD_UNDEFINED, // millisecond
826            timezone);
827    }
828
829    /**
830     * Create a Java instance of XML Schema builtin datatype <code>time</code>.
831     * @param hours number of hours
832     * @param minutes number of minutes
833     * @param seconds number of seconds
834     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
835     *
836     * @return <code>XMLGregorianCalendar</code> created from parameter values.
837     *
838     * @see DatatypeConstants#FIELD_UNDEFINED
839     *
840     * @throws IllegalArgumentException if any parameter is outside value
841     * constraints for the field as specified in
842     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
843     */
844    public static XMLGregorianCalendar createTime(
845        int hours,
846        int minutes,
847        int seconds,
848                int timezone) {
849
850                return new XMLGregorianCalendarImpl(
851                        DatatypeConstants.FIELD_UNDEFINED, // Year
852                        DatatypeConstants.FIELD_UNDEFINED, // Month
853                        DatatypeConstants.FIELD_UNDEFINED, // Day
854                        hours,
855                        minutes,
856                        seconds,
857                        DatatypeConstants.FIELD_UNDEFINED, //Millisecond
858                        timezone);
859    }
860
861    /**
862     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
863     *
864     * @param hours number of hours
865     * @param minutes number of minutes
866     * @param seconds number of seconds
867     * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
868     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
869     *
870     * @return <code>XMLGregorianCalendar</code> created from parameter values.
871     *
872     * @see DatatypeConstants#FIELD_UNDEFINED
873     *
874     * @throws IllegalArgumentException if any parameter is outside value
875     * constraints for the field as specified in
876     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
877     */
878    public static XMLGregorianCalendar createTime(
879        int hours,
880        int minutes,
881        int seconds,
882        BigDecimal fractionalSecond,
883        int timezone) {
884
885        return new XMLGregorianCalendarImpl(
886            null,            // Year
887            DatatypeConstants.FIELD_UNDEFINED, // month
888            DatatypeConstants.FIELD_UNDEFINED, // day
889            hours,
890            minutes,
891            seconds,
892            fractionalSecond,
893            timezone);
894    }
895
896    /**
897     * <p>Create a Java instance of XML Schema builtin datatype time.</p>
898     *
899     * @param hours number of hours
900     * @param minutes number of minutes
901     * @param seconds number of seconds
902     * @param milliseconds number of milliseconds
903     * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
904     *
905     * @return <code>XMLGregorianCalendar</code> created from parameter values.
906     *
907     * @see DatatypeConstants#FIELD_UNDEFINED
908     *
909     * @throws IllegalArgumentException if any parameter is outside value
910     * constraints for the field as specified in
911     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
912     */
913    public static XMLGregorianCalendar createTime(
914        int hours,
915        int minutes,
916        int seconds,
917        int milliseconds,
918        int timezone) {
919
920        return new XMLGregorianCalendarImpl(
921                DatatypeConstants.FIELD_UNDEFINED, // year
922                DatatypeConstants.FIELD_UNDEFINED, // month
923                DatatypeConstants.FIELD_UNDEFINED, // day
924                hours,
925                minutes,
926                seconds,
927                milliseconds,
928                timezone);
929    }
930
931    // Accessors
932
933    /**
934     * <p>Return high order component for XML Schema 1.0 dateTime datatype field for
935     * <code>year</code>.
936     * <code>null</code> if this optional part of the year field is not defined.</p>
937     *
938     * <p>Value constraints for this value are summarized in
939     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
940     * @return eon of this <code>XMLGregorianCalendar</code>. The value
941     * returned is an integer multiple of 10^9.
942     *
943     * @see #getYear()
944     * @see #getEonAndYear()
945     */
946    public BigInteger getEon() {
947           return eon;
948    }
949
950    /**
951     * <p>Return low order component for XML Schema 1.0 dateTime datatype field for
952     * <code>year</code> or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
953     *
954     * <p>Value constraints for this value are summarized in
955     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
956     *
957     * @return year  of this <code>XMLGregorianCalendar</code>.
958     *
959     * @see #getEon()
960     * @see #getEonAndYear()
961     */
962    public int getYear() {
963           return year;
964    }
965
966    /**
967     * <p>Return XML Schema 1.0 dateTime datatype field for
968     * <code>year</code>.</p>
969     *
970     * <p>Value constraints for this value are summarized in
971     * <a href="#datetimefield-year">year field of date/time field mapping table</a>.</p>
972     *
973     * @return sum of <code>eon</code> and <code>BigInteger.valueOf(year)</code>
974     * when both fields are defined. When only <code>year</code> is defined,
975     * return it. When both <code>eon</code> and <code>year</code> are not
976     * defined, return <code>null</code>.
977     *
978     * @see #getEon()
979     * @see #getYear()
980     */
981    public BigInteger getEonAndYear() {
982
983                // both are defined
984                if (year != DatatypeConstants.FIELD_UNDEFINED
985                        && eon != null) {
986
987                        return eon.add(BigInteger.valueOf((long) year));
988                }
989
990                // only year is defined
991                if (year != DatatypeConstants.FIELD_UNDEFINED
992                        && eon == null) {
993
994                        return BigInteger.valueOf((long) year);
995                }
996
997        // neither are defined
998        // or only eon is defined which is not valid without a year
999                return null;
1000    }
1001
1002    /**
1003     * <p>Return number of month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1004     *
1005     * <p>Value constraints for this value are summarized in
1006     * <a href="#datetimefield-month">month field of date/time field mapping table</a>.</p>
1007     *
1008     * @return year  of this <code>XMLGregorianCalendar</code>.
1009     *
1010     */
1011    public int getMonth() {
1012        return month;
1013    }
1014
1015    /**
1016     * Return day in month or {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1017     *
1018     * <p>Value constraints for this value are summarized in
1019     * <a href="#datetimefield-day">day field of date/time field mapping table</a>.</p>
1020     *
1021     * @see #setDay(int)
1022     */
1023    public int getDay() {
1024        return day;
1025    }
1026
1027    /**
1028     * Return timezone offset in minutes or
1029     * {@link DatatypeConstants#FIELD_UNDEFINED} if this optional field is not defined.
1030     *
1031     * <p>Value constraints for this value are summarized in
1032     * <a href="#datetimefield-timezone">timezone field of date/time field mapping table</a>.</p>
1033     *
1034     * @see #setTimezone(int)
1035     */
1036    public int getTimezone() {
1037        return timezone;
1038    }
1039
1040    /**
1041     * Return hours or {@link DatatypeConstants#FIELD_UNDEFINED}.
1042     * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1043     *
1044     * <p>Value constraints for this value are summarized in
1045     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.</p>
1046     * @see #setTime(int, int, int)
1047     */
1048    public int getHour() {
1049        return hour;
1050    }
1051
1052    /**
1053     * Return minutes or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p>
1054     * Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1055     *
1056     * <p>Value constraints for this value are summarized in
1057     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.</p>
1058     * @see #setTime(int, int, int)
1059     */
1060    public int getMinute() {
1061        return minute;
1062    }
1063
1064    /**
1065     * <p>Return seconds or {@link DatatypeConstants#FIELD_UNDEFINED}.<\p>
1066     *
1067     * <p>Returns {@link DatatypeConstants#FIELD_UNDEFINED} if this field is not defined.
1068     * When this field is not defined, the optional xs:dateTime
1069     * fractional seconds field, represented by
1070     * {@link #getFractionalSecond()} and {@link #getMillisecond()},
1071     * must not be defined.</p>
1072     *
1073     * <p>Value constraints for this value are summarized in
1074     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1075     *
1076     * @return Second  of this <code>XMLGregorianCalendar</code>.
1077     *
1078     * @see #getFractionalSecond()
1079     * @see #getMillisecond()
1080     * @see #setTime(int, int, int)
1081     */
1082    public int getSecond() {
1083           return second;
1084    }
1085
1086    /**
1087     * @return result of adding second and fractional second field
1088     */
1089    private BigDecimal getSeconds() {
1090        if (second == DatatypeConstants.FIELD_UNDEFINED) {
1091            return DECIMAL_ZERO;
1092        }
1093        BigDecimal result = BigDecimal.valueOf((long) second);
1094        if (fractionalSecond != null) {
1095            return result.add(fractionalSecond);
1096        } else {
1097            return result;
1098        }
1099    }
1100
1101
1102    /**
1103     * <p>Return millisecond precision of {@link #getFractionalSecond()}.<\p>
1104     *
1105     * <p>This method represents a convenience accessor to infinite
1106     * precision fractional second value returned by
1107     * {@link #getFractionalSecond()}. The returned value is the rounded
1108     * down to milliseconds value of
1109     * {@link #getFractionalSecond()}. When {@link #getFractionalSecond()}
1110     * returns <code>null</code>, this method must return
1111     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1112     *
1113     * <p>Value constraints for this value are summarized in
1114     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1115     *
1116     * @return Millisecond  of this <code>XMLGregorianCalendar</code>.
1117     *
1118     * @see #getFractionalSecond()
1119     * @see #setTime(int, int, int)
1120     */
1121    public int getMillisecond() {
1122        if (fractionalSecond == null) {
1123            return DatatypeConstants.FIELD_UNDEFINED;
1124        } else {
1125            // TODO: Non-optimal solution for now.
1126            // Efficient implementation would only store as BigDecimal
1127            // when needed and millisecond otherwise.
1128            return fractionalSecond.movePointRight(3).intValue();
1129        }
1130    }
1131
1132    /**
1133     * <p>Return fractional seconds.</p>
1134     *
1135     * <p><code>null</code> is returned when this optional field is not defined.</p>
1136     *
1137     * <p>Value constraints are detailed in
1138     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.</p>
1139     *
1140     * <p>This optional field can only have a defined value when the
1141     * xs:dateTime second field, represented by ({@link #getSecond()},
1142     * does not return {@link DatatypeConstants#FIELD_UNDEFINED}).</p>
1143     *
1144     * @return fractional seconds  of this <code>XMLGregorianCalendar</code>.
1145     *
1146     * @see #getSecond()
1147     * @see #setTime(int, int, int, BigDecimal)
1148     */
1149    public BigDecimal getFractionalSecond() {
1150           return fractionalSecond;
1151    }
1152
1153    // setters
1154
1155    /**
1156     * <p>Set low and high order component of XSD <code>dateTime</code> year field.</p>
1157     *
1158     * <p>Unset this field by invoking the setter with a parameter value of <code>null</code>.</p>
1159     *
1160     * @param year value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1161     *
1162     * @throws IllegalArgumentException if <code>year</code> parameter is
1163     * outside value constraints for the field as specified in
1164     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1165     */
1166    public final void setYear(BigInteger year) {
1167        if (year == null) {
1168            this.eon = null;
1169            this.year = DatatypeConstants.FIELD_UNDEFINED;
1170        } else {
1171            BigInteger temp = year.remainder(BILLION_B);
1172            this.year = temp.intValue();
1173            setEon(year.subtract(temp));
1174        }
1175    }
1176
1177    /**
1178     * <p>Set year of XSD <code>dateTime</code> year field.</p>
1179     *
1180     * <p>Unset this field by invoking the setter with a parameter value of
1181     * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1182     *
1183     * <p>Note: if the absolute value of the <code>year</code> parameter
1184     * is less than 10^9, the eon component of the XSD year field is set to
1185     * <code>null</code> by this method.</p>
1186     *
1187     * @param year value constraints are summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1188     *   If year is {@link DatatypeConstants#FIELD_UNDEFINED}, then eon is set to <code>null</code>.
1189     */
1190    public final void setYear(int year) {
1191        if (year == DatatypeConstants.FIELD_UNDEFINED) {
1192            this.year = DatatypeConstants.FIELD_UNDEFINED;
1193            this.eon = null;
1194        }
1195        else if (Math.abs(year) < BILLION_I) {
1196            this.year = year;
1197            this.eon = null;
1198        } else {
1199            BigInteger theYear = BigInteger.valueOf((long) year);
1200            BigInteger remainder = theYear.remainder(BILLION_B);
1201            this.year = remainder.intValue();
1202            setEon(theYear.subtract(remainder));
1203        }
1204    }
1205
1206    /**
1207     * <p>Set high order part of XSD <code>dateTime</code> year field.</p>
1208     *
1209     * <p>Unset this field by invoking the setter with a parameter value of
1210     * <code>null</code>.</p>
1211     *
1212     * @param eon value constraints summarized in <a href="#datetimefield-year">year field of date/time field mapping table</a>.
1213     */
1214    private void setEon(BigInteger eon) {
1215        if (eon != null && eon.compareTo(BigInteger.ZERO) == 0) {
1216            // Treat ZERO as field being undefined.
1217            this.eon = null;
1218        } else {
1219            this.eon = eon;
1220        }
1221    }
1222
1223    /**
1224     * <p>Set month.</p>
1225     *
1226     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1227     *
1228     * @param month value constraints summarized in <a href="#datetimefield-month">month field of date/time field mapping table</a>.
1229     *
1230     * @throws IllegalArgumentException if <code>month</code> parameter is
1231     * outside value constraints for the field as specified in
1232     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1233     */
1234    public final void setMonth(int month) {
1235        if(month<DatatypeConstants.JANUARY || DatatypeConstants.DECEMBER<month)
1236            if(month!=DatatypeConstants.FIELD_UNDEFINED)
1237                invalidFieldValue(MONTH, month);
1238        this.month = month;
1239    }
1240
1241    /**
1242     * <p>Set days in month.</p>
1243     *
1244     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1245     *
1246     * @param day value constraints summarized in <a href="#datetimefield-day">day field of date/time field mapping table</a>.
1247     *
1248     * @throws IllegalArgumentException if <code>day</code> parameter is
1249     * outside value constraints for the field as specified in
1250     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1251     */
1252    public final void setDay(int day) {
1253        if(day<1 || 31<day)
1254            if(day!=DatatypeConstants.FIELD_UNDEFINED)
1255                invalidFieldValue(DAY,day);
1256        this.day = day;
1257    }
1258
1259    /**
1260     * <p>Set the number of minutes in the timezone offset.</p>
1261     *
1262     * <p>Unset this field by invoking the setter with a parameter value of {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
1263     *
1264     * @param offset value constraints summarized in <a href="#datetimefield-timezone">
1265     *   timezone field of date/time field mapping table</a>.
1266     *
1267     * @throws IllegalArgumentException if <code>offset</code> parameter is
1268     * outside value constraints for the field as specified in
1269     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1270     */
1271    public final void setTimezone(int offset) {
1272            if(offset<-14*60 || 14*60<offset)
1273            if(offset!=DatatypeConstants.FIELD_UNDEFINED)
1274                invalidFieldValue(TIMEZONE,offset);
1275        this.timezone = offset;
1276    }
1277
1278    /**
1279     * <p>Set time as one unit.</p>
1280     *
1281     * @param hour value constraints are summarized in
1282     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1283     * @param minute value constraints are summarized in
1284     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1285     * @param second value constraints are summarized in
1286     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1287     *
1288     * @see #setTime(int, int, int, BigDecimal)
1289     *
1290     * @throws IllegalArgumentException if any parameter is
1291     * outside value constraints for the field as specified in
1292     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1293     */
1294    public final void setTime(int hour, int minute, int second) {
1295        setTime(hour, minute, second, null);
1296    }
1297
1298    private void invalidFieldValue(int field, int value) {
1299        throw new IllegalArgumentException(
1300            DatatypeMessageFormatter.formatMessage(null, "InvalidFieldValue",
1301                new Object[]{ value, FIELD_NAME[field]})
1302        );
1303    }
1304
1305    private void testHour() {
1306
1307        // http://www.w3.org/2001/05/xmlschema-errata#e2-45
1308        if (getHour() == 24) {
1309            if (getMinute() != 0
1310                    || getSecond() != 0) {
1311                invalidFieldValue(HOUR, getHour());
1312            }
1313            // while 0-24 is acceptable in the lexical space, 24 is not valid in value space
1314            // W3C XML Schema Part 2, Section 3.2.7.1
1315            setHour(0, false);
1316            add(new DurationImpl(true, 0, 0, 1, 0, 0, 0));
1317        }
1318    }
1319
1320    public void setHour(int hour) {
1321
1322        setHour(hour, true);
1323    }
1324
1325    private void setHour(int hour, boolean validate) {
1326
1327        if (hour < 0 || hour > 24) {
1328            if (hour != DatatypeConstants.FIELD_UNDEFINED) {
1329                invalidFieldValue(HOUR, hour);
1330            }
1331        }
1332
1333        this.hour = hour;
1334
1335        if (validate) {
1336            testHour();
1337        }
1338    }
1339
1340    public void setMinute(int minute) {
1341        if(minute<0 || 59<minute)
1342            if(minute!=DatatypeConstants.FIELD_UNDEFINED)
1343                invalidFieldValue(MINUTE, minute);
1344        this.minute = minute;
1345    }
1346
1347    public void setSecond(int second) {
1348        if(second<0 || 60<second)   // leap second allows for 60
1349            if(second!=DatatypeConstants.FIELD_UNDEFINED)
1350                invalidFieldValue(SECOND, second);
1351        this.second  = second;
1352    }
1353
1354    /**
1355     * <p>Set time as one unit, including the optional infinite precison
1356     * fractional seconds.</p>
1357     *
1358     * @param hour value constraints are summarized in
1359     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1360     * @param minute value constraints are summarized in
1361     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1362     * @param second value constraints are summarized in
1363     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1364     * @param fractional value of <code>null</code> indicates this optional
1365     *                   field is not set.
1366     *
1367     * @throws IllegalArgumentException if any parameter is
1368     * outside value constraints for the field as specified in
1369     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1370     */
1371    public final void setTime(
1372            int hour,
1373            int minute,
1374            int second,
1375            BigDecimal fractional) {
1376
1377        setHour(hour, false);
1378
1379        setMinute(minute);
1380        if (second != 60) {
1381            setSecond(second);
1382        } else if ((hour == 23 && minute == 59) || (hour == 0 && minute == 0)) {
1383            setSecond(second);
1384        } else {
1385            invalidFieldValue(SECOND, second);
1386        }
1387
1388        setFractionalSecond(fractional);
1389
1390        // must test hour after setting seconds
1391        testHour();
1392    }
1393
1394
1395    /**
1396     * <p>Set time as one unit, including optional milliseconds.</p>
1397     *
1398     * @param hour value constraints are summarized in
1399     * <a href="#datetimefield-hour">hour field of date/time field mapping table</a>.
1400     * @param minute value constraints are summarized in
1401     * <a href="#datetimefield-minute">minute field of date/time field mapping table</a>.
1402     * @param second value constraints are summarized in
1403     * <a href="#datetimefield-second">second field of date/time field mapping table</a>.
1404     * @param millisecond value of {@link DatatypeConstants#FIELD_UNDEFINED} indicates this
1405     *                    optional field is not set.
1406     *
1407     * @throws IllegalArgumentException if any parameter is
1408     * outside value constraints for the field as specified in
1409     * <a href="#datetimefieldmapping">date/time field mapping table</a>.
1410     */
1411    public final void setTime(int hour, int minute, int second, int millisecond) {
1412
1413        setHour(hour, false);
1414
1415        setMinute(minute);
1416        if (second != 60) {
1417            setSecond(second);
1418        } else if ((hour == 23 && minute == 59) || (hour == 0 && minute == 0)) {
1419            setSecond(second);
1420        } else {
1421            invalidFieldValue(SECOND, second);
1422        }
1423        setMillisecond(millisecond);
1424
1425        // must test hour after setting seconds
1426        testHour();
1427    }
1428
1429    // comparisons
1430    /**
1431     * <p>Compare two instances of W3C XML Schema 1.0 date/time datatypes
1432     * according to partial order relation defined in
1433     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.3,
1434     * <i>Order relation on dateTime</i></a>.</p>
1435     *
1436     * <p><code>xsd:dateTime</code> datatype field mapping to accessors of
1437     * this class are defined in
1438     * <a href="#datetimefieldmapping">date/time field mapping table</a>.</p>
1439     *
1440     * @param rhs instance of <code>XMLGregorianCalendar</code> to compare
1441     *
1442     * @return the relationship between <code>lhs</code> and <code>rhs</code> as
1443     *   {@link DatatypeConstants#LESSER},
1444     *   {@link DatatypeConstants#EQUAL},
1445     *   {@link DatatypeConstants#GREATER} or
1446     *   {@link DatatypeConstants#INDETERMINATE}.
1447     *
1448     * @throws NullPointerException if <code>lhs</code> or <code>rhs</code>
1449     * parameters are null.
1450     */
1451    public int compare(XMLGregorianCalendar rhs) {
1452
1453        XMLGregorianCalendar lhs = this;
1454
1455        int result = DatatypeConstants.INDETERMINATE;
1456        XMLGregorianCalendarImpl P = (XMLGregorianCalendarImpl) lhs;
1457        XMLGregorianCalendarImpl Q = (XMLGregorianCalendarImpl) rhs;
1458
1459        if (P.getTimezone() == Q.getTimezone()) {
1460            // Optimization:
1461            // both instances are in same timezone or
1462            // both are FIELD_UNDEFINED.
1463            // Avoid costly normalization of timezone to 'Z' time.
1464            return internalCompare(P, Q);
1465
1466        } else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED &&
1467                Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
1468
1469            // Both instances have different timezones.
1470            // Normalize to UTC time and compare.
1471            P = (XMLGregorianCalendarImpl) P.normalize();
1472            Q = (XMLGregorianCalendarImpl) Q.normalize();
1473            return internalCompare(P, Q);
1474        } else if (P.getTimezone() != DatatypeConstants.FIELD_UNDEFINED) {
1475
1476            if (P.getTimezone() != 0) {
1477                P = (XMLGregorianCalendarImpl) P.normalize();
1478            }
1479
1480            // C. step 1
1481            XMLGregorianCalendar MinQ = Q.normalizeToTimezone(DatatypeConstants.MIN_TIMEZONE_OFFSET);
1482            result = internalCompare(P, MinQ);
1483            if (result == DatatypeConstants.LESSER) {
1484                return result;
1485            }
1486
1487            // C. step 2
1488            XMLGregorianCalendar MaxQ = Q.normalizeToTimezone(DatatypeConstants.MAX_TIMEZONE_OFFSET);
1489            result = internalCompare(P, MaxQ);
1490            if (result == DatatypeConstants.GREATER) {
1491                return result;
1492            } else {
1493                // C. step 3
1494                return DatatypeConstants.INDETERMINATE;
1495            }
1496        } else { // Q.getTimezone() != DatatypeConstants.FIELD_UNDEFINED
1497            // P has no timezone and Q does.
1498            if (Q.getTimezone() != 0) {
1499                Q = (XMLGregorianCalendarImpl) Q.normalizeToTimezone(Q.getTimezone());
1500            }
1501
1502            // D. step 1
1503            XMLGregorianCalendar MaxP = P.normalizeToTimezone(DatatypeConstants.MAX_TIMEZONE_OFFSET);
1504            result = internalCompare(MaxP, Q);
1505            if (result == DatatypeConstants.LESSER) {
1506                return result;
1507            }
1508
1509            // D. step 2
1510            XMLGregorianCalendar MinP = P.normalizeToTimezone(DatatypeConstants.MIN_TIMEZONE_OFFSET);
1511            result = internalCompare(MinP, Q);
1512            if (result == DatatypeConstants.GREATER) {
1513                return result;
1514            } else {
1515                // D. step 3
1516                return DatatypeConstants.INDETERMINATE;
1517            }
1518        }
1519    }
1520
1521    /**
1522     * <p>Normalize this instance to UTC.</p>
1523     *
1524     * <p>2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z</p>
1525     * <p>Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).</p>
1526     */
1527    public XMLGregorianCalendar normalize() {
1528
1529        XMLGregorianCalendar normalized = normalizeToTimezone(timezone);
1530
1531        // if timezone was undefined, leave it undefined
1532        if (getTimezone() == DatatypeConstants.FIELD_UNDEFINED) {
1533            normalized.setTimezone(DatatypeConstants.FIELD_UNDEFINED);
1534        }
1535
1536        // if milliseconds was undefined, leave it undefined
1537        if (getMillisecond() == DatatypeConstants.FIELD_UNDEFINED) {
1538            normalized.setMillisecond(DatatypeConstants.FIELD_UNDEFINED);
1539        }
1540
1541        return normalized;
1542    }
1543
1544        /**
1545         * <p>Normalize this instance to UTC.</p>
1546         *
1547         * <p>2000-03-04T23:00:00+03:00 normalizes to 2000-03-04T20:00:00Z</p>
1548         * <p>Implements W3C XML Schema Part 2, Section 3.2.7.3 (A).</p>
1549         */
1550    private XMLGregorianCalendar normalizeToTimezone(int timezone) {
1551
1552        int minutes = timezone;
1553        XMLGregorianCalendar result = (XMLGregorianCalendar) this.clone();
1554
1555        // normalizing to UTC time negates the timezone offset before
1556        // addition.
1557        minutes = -minutes;
1558        Duration d = new DurationImpl(minutes >= 0, // isPositive
1559                0, //years
1560                0, //months
1561                0, //days
1562                0, //hours
1563                minutes < 0 ? -minutes : minutes, // absolute
1564                0  //seconds
1565        );
1566        result.add(d);
1567
1568        // set to zulu UTC time.
1569        result.setTimezone(0);
1570        return result;
1571    }
1572
1573    /**
1574     *
1575     *  <p>Implements Step B from http://www.w3.org/TR/xmlschema-2/#dateTime-order </p>
1576     * @param P calendar instance with normalized timezone offset or
1577     *          having same timezone as Q
1578     * @param Q calendar instance with normalized timezone offset or
1579     *          having same timezone as P
1580     *
1581     * @return result of comparing P and Q, value of
1582     *   {@link DatatypeConstants#EQUAL},
1583     *   {@link DatatypeConstants#LESSER},
1584     *   {@link DatatypeConstants#GREATER} or
1585     *   {@link DatatypeConstants#INDETERMINATE}.
1586     */
1587    private static int internalCompare(XMLGregorianCalendar P,
1588                                       XMLGregorianCalendar Q) {
1589
1590        int result;
1591
1592        // compare Year.
1593        if (P.getEon() == Q.getEon()) {
1594
1595            // Eon field is only equal when null.
1596            // optimized case for comparing year not requiring eon field.
1597            result = compareField(P.getYear(), Q.getYear());
1598            if (result != DatatypeConstants.EQUAL) {
1599                return result;
1600            }
1601        } else {
1602            result = compareField(P.getEonAndYear(), Q.getEonAndYear());
1603            if (result != DatatypeConstants.EQUAL) {
1604                return result;
1605            }
1606        }
1607
1608        result = compareField(P.getMonth(), Q.getMonth());
1609        if (result != DatatypeConstants.EQUAL) {
1610            return result;
1611        }
1612
1613        result = compareField(P.getDay(), Q.getDay());
1614        if (result != DatatypeConstants.EQUAL) {
1615            return result;
1616        }
1617
1618        result = compareField(P.getHour(), Q.getHour());
1619        if (result != DatatypeConstants.EQUAL) {
1620            return result;
1621        }
1622
1623        result = compareField(P.getMinute(), Q.getMinute());
1624        if (result != DatatypeConstants.EQUAL) {
1625            return result;
1626        }
1627        result = compareField(P.getSecond(), Q.getSecond());
1628        if (result != DatatypeConstants.EQUAL) {
1629            return result;
1630        }
1631
1632        result = compareField(P.getFractionalSecond(), Q.getFractionalSecond());
1633        return result;
1634    }
1635
1636    /**
1637     * <p>Implement Step B from
1638     * http://www.w3.org/TR/xmlschema-2/#dateTime-order.</p>
1639     */
1640    private static int compareField(int Pfield, int Qfield) {
1641        if (Pfield == Qfield) {
1642
1643            //fields are either equal in value or both undefined.
1644            // Step B. 1.1 AND optimized result of performing 1.1-1.4.
1645            return DatatypeConstants.EQUAL;
1646        } else {
1647            if (Pfield == DatatypeConstants.FIELD_UNDEFINED || Qfield == DatatypeConstants.FIELD_UNDEFINED) {
1648                // Step B. 1.2
1649                return DatatypeConstants.INDETERMINATE;
1650            } else {
1651                // Step B. 1.3-4.
1652                return (Pfield < Qfield ? DatatypeConstants.LESSER : DatatypeConstants.GREATER);
1653            }
1654        }
1655    }
1656
1657    private static int compareField(BigInteger Pfield, BigInteger Qfield) {
1658        if (Pfield == null) {
1659            return (Qfield == null ? DatatypeConstants.EQUAL : DatatypeConstants.INDETERMINATE);
1660        }
1661        if (Qfield == null) {
1662            return DatatypeConstants.INDETERMINATE;
1663        }
1664        return Pfield.compareTo(Qfield);
1665    }
1666
1667    private static int compareField(BigDecimal Pfield, BigDecimal Qfield) {
1668        // optimization. especially when both arguments are null.
1669        if (Pfield == Qfield) {
1670            return DatatypeConstants.EQUAL;
1671        }
1672
1673        if (Pfield == null) {
1674            Pfield = DECIMAL_ZERO;
1675        }
1676
1677        if (Qfield == null) {
1678            Qfield = DECIMAL_ZERO;
1679        }
1680
1681        return Pfield.compareTo(Qfield);
1682    }
1683
1684    /**
1685     * <p>Indicates whether parameter <code>obj</code> is "equal to" this one.</p>
1686     *
1687     * @param obj to compare.
1688     *
1689     * @return <code>true</code> when <code>compare(this,(XMLGregorianCalendar)obj) == EQUAL.</code>.
1690     */
1691    public boolean equals(Object obj) {
1692
1693        if (obj == null || !(obj instanceof XMLGregorianCalendar)) {
1694            return false;
1695        }
1696        if (obj == this) {
1697            return true;
1698        }
1699        return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
1700    }
1701
1702    /**
1703     * <p>Returns a hash code consistent with the definition of the equals method.</p>
1704     *
1705     * @return hash code of this object.
1706     */
1707    public int hashCode() {
1708
1709        // Following two dates compare to EQUALS since in different timezones.
1710        // 2000-01-15T12:00:00-05:00 == 2000-01-15T13:00:00-04:00
1711        //
1712        // Must ensure both instances generate same hashcode by normalizing
1713        // this to UTC timezone.
1714        int timezone = getTimezone();
1715        if (timezone == DatatypeConstants.FIELD_UNDEFINED) {
1716            timezone = 0;
1717        }
1718        XMLGregorianCalendar gc = this;
1719        if (timezone != 0) {
1720            gc = this.normalizeToTimezone(getTimezone());
1721        }
1722        return gc.getYear() + gc.getMonth() + gc.getDay() +
1723                gc.getHour() + gc.getMinute() + gc.getSecond();
1724    }
1725
1726
1727    /**
1728     * <p>Constructs a new XMLGregorianCalendar object by
1729     * parsing its lexical string representation as defined in
1730     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
1731     * <i>Lexical Representation</i>.</a></p>
1732     *
1733     * <p>The string representation may not have any leading and trailing whitespaces.</p>
1734     *
1735     * <p>The parsing is done field by field so that
1736     * the following holds for any lexically correct string x:</p>
1737     * <pre>
1738     * new XMLGregorianCalendar(x).toXMLFormat().equals(x)
1739     * </pre>
1740     * Except for the noted lexical/canonical representation mismatches
1741     * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
1742     * XML Schema 1.0 errata, Section 3.2.7.2</a>.
1743     *
1744     * <p>Returns a non-null valid XMLGregorianCalendar object that holds the value
1745     * indicated by the lexicalRepresentation parameter.</p>
1746     *
1747     * @param lexicalRepresentation Lexical representation of one the 8 XML Schema calendar datatypes.
1748     *
1749     * @return <code>XMLGregorianCalendar</code> created from parsing <code>lexicalRepresentation</code> parameter.
1750     *
1751     * @throws IllegalArgumentException
1752     *      If the given string does not conform to the aforementioned
1753     *      specification.
1754     * @throws NullPointerException
1755     *      If the given string is null.
1756     */
1757    public static XMLGregorianCalendar parse(String lexicalRepresentation) {
1758
1759                return new XMLGregorianCalendarImpl(lexicalRepresentation);
1760    }
1761
1762    /**
1763     * <p>Return the lexical representation of <code>this</code> instance.
1764     * The format is specified in
1765     * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
1766     * <i>Lexical Representation</i>".</a></p>
1767     *
1768     * <p>Specific target lexical representation format is determined by
1769     * {@link #getXMLSchemaType()}.</p>
1770     *
1771     * @return XML, as <code>String</code>, representation of this <code>XMLGregorianCalendar</code>
1772     *
1773     * @throws java.lang.IllegalStateException if the combination of set fields
1774     *    does not match one of the eight defined XML Schema builtin date/time datatypes.
1775     */
1776    public String toXMLFormat() {
1777
1778        QName typekind = getXMLSchemaType();
1779
1780        String formatString = null;
1781        // Fix 4971612: invalid SCCS macro substitution in data string
1782        //   no %{alpha}% to avoid SCCS macro substitution
1783        if (typekind == DatatypeConstants.DATETIME) {
1784            formatString = "%Y-%M-%DT%h:%m:%s" + "%z";
1785        } else if (typekind == DatatypeConstants.DATE) {
1786            formatString = "%Y-%M-%D" + "%z";
1787        } else if (typekind == DatatypeConstants.TIME) {
1788            formatString = "%h:%m:%s" + "%z";
1789        } else if (typekind == DatatypeConstants.GMONTH) {
1790            formatString = "--%M" + "%z";
1791        } else if (typekind == DatatypeConstants.GDAY) {
1792            formatString = "---%D" + "%z";
1793        } else if (typekind == DatatypeConstants.GYEAR) {
1794            formatString = "%Y" + "%z";
1795        } else if (typekind == DatatypeConstants.GYEARMONTH) {
1796            formatString = "%Y-%M" + "%z";
1797        } else if (typekind == DatatypeConstants.GMONTHDAY) {
1798            formatString = "--%M-%D" + "%z";
1799        }
1800        return format(formatString);
1801    }
1802
1803    /**
1804     * <p>Return the name of the XML Schema date/time type that this instance
1805     * maps to. Type is computed based on fields that are set.</p>
1806     *
1807     * <table border="2" rules="all" cellpadding="2">
1808     *   <thead>
1809     *     <tr>
1810     *       <th align="center" colspan="7">
1811     *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
1812     *         <i>(timezone is optional for all date/time datatypes)</i>
1813     *       </th>
1814     *     </tr>
1815     *   </thead>
1816     *   <tbody>
1817     *     <tr>
1818     *       <td>Datatype</td>
1819     *       <td>year</td>
1820     *       <td>month</td>
1821     *       <td>day</td>
1822     *       <td>hour</td>
1823     *       <td>minute</td>
1824     *       <td>second</td>
1825     *     </tr>
1826     *     <tr>
1827     *       <td>{@link DatatypeConstants#DATETIME}</td>
1828     *       <td>X</td>
1829     *       <td>X</td>
1830     *       <td>X</td>
1831     *       <td>X</td>
1832     *       <td>X</td>
1833     *       <td>X</td>
1834     *     </tr>
1835     *     <tr>
1836     *       <td>{@link DatatypeConstants#DATE}</td>
1837     *       <td>X</td>
1838     *       <td>X</td>
1839     *       <td>X</td>
1840     *       <td></td>
1841     *       <td></td>
1842     *       <td></td>
1843     *     </tr>
1844     *     <tr>
1845     *       <td>{@link DatatypeConstants#TIME}</td>
1846     *       <td></td>
1847     *       <td></td>
1848     *       <td></td>
1849     *       <td>X</td>
1850     *       <td>X</td>
1851     *       <td>X</td>
1852     *     </tr>
1853     *     <tr>
1854     *       <td>{@link DatatypeConstants#GYEARMONTH}</td>
1855     *       <td>X</td>
1856     *       <td>X</td>
1857     *       <td></td>
1858     *       <td></td>
1859     *       <td></td>
1860     *       <td></td>
1861     *     </tr>
1862     *     <tr>
1863     *       <td>{@link DatatypeConstants#GMONTHDAY}</td>
1864     *       <td></td>
1865     *       <td>X</td>
1866     *       <td>X</td>
1867     *       <td></td>
1868     *       <td></td>
1869     *       <td></td>
1870     *     </tr>
1871     *     <tr>
1872     *       <td>{@link DatatypeConstants#GYEAR}</td>
1873     *       <td>X</td>
1874     *       <td></td>
1875     *       <td></td>
1876     *       <td></td>
1877     *       <td></td>
1878     *       <td></td>
1879     *     </tr>
1880     *     <tr>
1881     *       <td>{@link DatatypeConstants#GMONTH}</td>
1882     *       <td></td>
1883     *       <td>X</td>
1884     *       <td></td>
1885     *       <td></td>
1886     *       <td></td>
1887     *       <td></td>
1888     *     </tr>
1889     *     <tr>
1890     *       <td>{@link DatatypeConstants#GDAY}</td>
1891     *       <td></td>
1892     *       <td></td>
1893     *       <td>X</td>
1894     *       <td></td>
1895     *       <td></td>
1896     *       <td></td>
1897     *     </tr>
1898     *   </tbody>
1899     * </table>
1900     *
1901     * @throws java.lang.IllegalStateException if the combination of set fields
1902     *    does not match one of the eight defined XML Schema builtin
1903     *    date/time datatypes.
1904     * @return One of the following class constants:
1905     *   {@link DatatypeConstants#DATETIME},
1906     *   {@link DatatypeConstants#TIME},
1907     *   {@link DatatypeConstants#DATE},
1908     *   {@link DatatypeConstants#GYEARMONTH},
1909     *   {@link DatatypeConstants#GMONTHDAY},
1910     *   {@link DatatypeConstants#GYEAR},
1911     *   {@link DatatypeConstants#GMONTH} or
1912     *   {@link DatatypeConstants#GDAY}.
1913     */
1914    public QName getXMLSchemaType() {
1915
1916        int mask =
1917            (year != DatatypeConstants.FIELD_UNDEFINED ?   0x20 : 0 )|
1918            (month != DatatypeConstants.FIELD_UNDEFINED ?  0x10 : 0 )|
1919            (day != DatatypeConstants.FIELD_UNDEFINED ?    0x08 : 0 )|
1920            (hour != DatatypeConstants.FIELD_UNDEFINED ?   0x04 : 0 )|
1921            (minute != DatatypeConstants.FIELD_UNDEFINED ? 0x02 : 0 )|
1922            (second != DatatypeConstants.FIELD_UNDEFINED ? 0x01 : 0 );
1923
1924        switch(mask) {
1925        case 0x3F:
1926                return DatatypeConstants.DATETIME;
1927        case 0x38:
1928                return DatatypeConstants.DATE;
1929        case 0x07:
1930                return DatatypeConstants.TIME;
1931        case 0x30:
1932                return DatatypeConstants.GYEARMONTH;
1933        case 0x18:
1934                return DatatypeConstants.GMONTHDAY;
1935        case 0x20:
1936                return DatatypeConstants.GYEAR;
1937        case 0x10:
1938                return DatatypeConstants.GMONTH;
1939        case 0x08:
1940                return DatatypeConstants.GDAY;
1941        default:
1942            throw new IllegalStateException(
1943                this.getClass().getName()
1944                + "#getXMLSchemaType() :"
1945                + DatatypeMessageFormatter.formatMessage(null, "InvalidXGCFields", null)
1946            );
1947        }
1948    }
1949
1950
1951    /**
1952     * Validate instance by <code>getXMLSchemaType()</code> constraints.
1953     * @return true if data values are valid.
1954     */
1955    public final boolean isValid() {
1956        // since setters do not allow for invalid values,
1957        // (except for exceptional case of year field of zero),
1958        // no need to check for anything except for constraints
1959        // between fields.
1960
1961        // check if days in month is valid. Can be dependent on leap year.
1962        if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) {
1963            if (year != DatatypeConstants.FIELD_UNDEFINED) {
1964                if (eon == null) {
1965                    if (day > maximumDayInMonthFor(year, month)) {
1966                        return false;
1967                    }
1968                }
1969                else if (day > maximumDayInMonthFor(getEonAndYear(), month)) {
1970                    return false;
1971                }
1972            }
1973            // Use 2000 as a default since it's a leap year.
1974            else if (day > maximumDayInMonthFor(2000, month)) {
1975                return false;
1976            }
1977        }
1978
1979        // http://www.w3.org/2001/05/xmlschema-errata#e2-45
1980        if (hour == 24 && (minute != 0 || second != 0 ||
1981                (fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) {
1982            return false;
1983        }
1984
1985        // XML Schema 1.0 specification defines year value of zero as
1986        // invalid. Allow this class to set year field to zero
1987        // since XML Schema 1.0 errata states that lexical zero will
1988        // be allowed in next version and treated as 1 B.C.E.
1989        if (eon == null && year == 0) {
1990            return false;
1991        }
1992        return true;
1993    }
1994
1995    /**
1996     * <p>Add <code>duration</code> to this instance.<\p>
1997     *
1998     * <p>The computation is specified in
1999     * <a href="http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes">XML Schema 1.0 Part 2, Appendix E,
2000     * <i>Adding durations to dateTimes</i>></a>.
2001     * <a href="#datetimefieldsmapping">date/time field mapping table</a>
2002     * defines the mapping from XML Schema 1.0 <code>dateTime</code> fields
2003     * to this class' representation of those fields.</p>
2004     *
2005     * @param duration Duration to add to this <code>XMLGregorianCalendar</code>.
2006     *
2007     * @throws NullPointerException  when <code>duration</code> parameter is <code>null</code>.
2008     */
2009    public void add(Duration duration) {
2010
2011        /*
2012           * Extracted from
2013           * http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes
2014           * to ensure implemented properly. See spec for definitions of methods
2015           * used in algorithm.
2016           *
2017           * Given a dateTime S and a duration D, specifies how to compute a
2018           * dateTime E where E is the end of the time period with start S and
2019           * duration D i.e. E = S + D.
2020           *
2021           * The following is the precise specification.
2022           * These steps must be followed in the same order.
2023           * If a field in D is not specified, it is treated as if it were zero.
2024           * If a field in S is not specified, it is treated in the calculation
2025           * as if it were the minimum allowed value in that field, however,
2026           * after the calculation is concluded, the corresponding field in
2027           * E is removed (set to unspecified).
2028           *
2029           * Months (may be modified additionally below)
2030               *  temp := S[month] + D[month]
2031               *  E[month] := modulo(temp, 1, 13)
2032               *  carry := fQuotient(temp, 1, 13)
2033           */
2034
2035        boolean fieldUndefined[] = {
2036                false,
2037                false,
2038                false,
2039                false,
2040                false,
2041                false
2042        };
2043
2044        int signum = duration.getSign();
2045
2046        int startMonth = getMonth();
2047        if (startMonth == DatatypeConstants.FIELD_UNDEFINED) {
2048            startMonth = DatatypeConstants.JANUARY;
2049            fieldUndefined[MONTH] = true;
2050        }
2051
2052        BigInteger dMonths = sanitize(duration.getField(DatatypeConstants.MONTHS), signum);
2053        BigInteger temp = BigInteger.valueOf((long) startMonth).add(dMonths);
2054        setMonth(temp.subtract(BigInteger.ONE).mod(TWELVE).intValue() + 1);
2055        BigInteger carry =
2056                new BigDecimal(temp.subtract(BigInteger.ONE))
2057                        .divide(DECIMAL_TWELVE, RoundingMode.FLOOR).toBigInteger();
2058
2059        /* Years (may be modified additionally below)
2060            *  E[year] := S[year] + D[year] + carry
2061            */
2062        BigInteger startYear = getEonAndYear();
2063        if (startYear == null) {
2064            fieldUndefined[YEAR] = true;
2065            startYear = BigInteger.ZERO;
2066        }
2067        BigInteger dYears = sanitize(duration.getField(DatatypeConstants.YEARS), signum);
2068        BigInteger endYear = startYear.add(dYears).add(carry);
2069        setYear(endYear);
2070
2071        /* Zone
2072               *  E[zone] := S[zone]
2073           *
2074           * no-op since adding to this, not to a new end point.
2075           */
2076
2077        /* Seconds
2078            *  temp := S[second] + D[second]
2079            *  E[second] := modulo(temp, 60)
2080            *  carry := fQuotient(temp, 60)
2081            */
2082        BigDecimal startSeconds;
2083        if (getSecond() == DatatypeConstants.FIELD_UNDEFINED) {
2084            fieldUndefined[SECOND] = true;
2085            startSeconds = DECIMAL_ZERO;
2086        } else {
2087            // seconds + fractionalSeconds
2088            startSeconds = getSeconds();
2089        }
2090
2091        // Duration seconds is SECONDS + FRACTIONALSECONDS.
2092        BigDecimal dSeconds = DurationImpl.sanitize((BigDecimal) duration.getField(DatatypeConstants.SECONDS), signum);
2093        BigDecimal tempBD = startSeconds.add(dSeconds);
2094        BigDecimal fQuotient =
2095                new BigDecimal(new BigDecimal(tempBD.toBigInteger()).divide(DECIMAL_SIXTY, RoundingMode.FLOOR).toBigInteger());
2096        BigDecimal endSeconds = tempBD.subtract(fQuotient.multiply(DECIMAL_SIXTY));
2097
2098        carry = fQuotient.toBigInteger();
2099        setSecond(endSeconds.intValue());
2100        BigDecimal tempFracSeconds = endSeconds.subtract(new BigDecimal(BigInteger.valueOf((long) getSecond())));
2101        if (tempFracSeconds.compareTo(DECIMAL_ZERO) < 0) {
2102            setFractionalSecond(DECIMAL_ONE.add(tempFracSeconds));
2103            if (getSecond() == 0) {
2104                setSecond(59);
2105                carry = carry.subtract(BigInteger.ONE);
2106            } else {
2107                setSecond(getSecond() - 1);
2108            }
2109        } else {
2110            setFractionalSecond(tempFracSeconds);
2111        }
2112
2113        /* Minutes
2114               *  temp := S[minute] + D[minute] + carry
2115               *  E[minute] := modulo(temp, 60)
2116               *  carry := fQuotient(temp, 60)
2117           */
2118        int startMinutes = getMinute();
2119        if (startMinutes == DatatypeConstants.FIELD_UNDEFINED) {
2120            fieldUndefined[MINUTE] = true;
2121            startMinutes = 0;
2122        }
2123        BigInteger dMinutes = sanitize(duration.getField(DatatypeConstants.MINUTES), signum);
2124
2125        temp = BigInteger.valueOf(startMinutes).add(dMinutes).add(carry);
2126        setMinute(temp.mod(SIXTY).intValue());
2127        carry = new BigDecimal(temp).divide(DECIMAL_SIXTY, RoundingMode.FLOOR).toBigInteger();
2128
2129        /* Hours
2130               *  temp := S[hour] + D[hour] + carry
2131               *  E[hour] := modulo(temp, 24)
2132               *  carry := fQuotient(temp, 24)
2133           */
2134        int startHours = getHour();
2135        if (startHours == DatatypeConstants.FIELD_UNDEFINED) {
2136            fieldUndefined[HOUR] = true;
2137            startHours = 0;
2138        }
2139        BigInteger dHours = sanitize(duration.getField(DatatypeConstants.HOURS), signum);
2140
2141        temp = BigInteger.valueOf(startHours).add(dHours).add(carry);
2142        setHour(temp.mod(TWENTY_FOUR).intValue(), false);
2143        carry = new BigDecimal(temp).divide(DECIMAL_TWENTY_FOUR,
2144                RoundingMode.FLOOR).toBigInteger();
2145
2146        /* Days
2147           *  if S[day] > maximumDayInMonthFor(E[year], E[month])
2148           *       + tempDays := maximumDayInMonthFor(E[year], E[month])
2149           *  else if S[day] < 1
2150           *       + tempDays := 1
2151           *  else
2152           *       + tempDays := S[day]
2153           *  E[day] := tempDays + D[day] + carry
2154           *  START LOOP
2155           *       + IF E[day] < 1
2156           *             # E[day] := E[day] +
2157            *                 maximumDayInMonthFor(E[year], E[month] - 1)
2158           *             # carry := -1
2159           *       + ELSE IF E[day] > maximumDayInMonthFor(E[year], E[month])
2160           *             # E[day] :=
2161            *                    E[day] - maximumDayInMonthFor(E[year], E[month])
2162           *             # carry := 1
2163           *       + ELSE EXIT LOOP
2164           *       + temp := E[month] + carry
2165           *       + E[month] := modulo(temp, 1, 13)
2166           *       + E[year] := E[year] + fQuotient(temp, 1, 13)
2167           *       + GOTO START LOOP
2168           */
2169        BigInteger tempDays;
2170        int startDay = getDay();
2171        if (startDay == DatatypeConstants.FIELD_UNDEFINED) {
2172            fieldUndefined[DAY] = true;
2173            startDay = 1;
2174        }
2175        BigInteger dDays = sanitize(duration.getField(DatatypeConstants.DAYS), signum);
2176        int maxDayInMonth = maximumDayInMonthFor(getEonAndYear(), getMonth());
2177        if (startDay > maxDayInMonth) {
2178            tempDays = BigInteger.valueOf(maxDayInMonth);
2179        } else if (startDay < 1) {
2180            tempDays = BigInteger.ONE;
2181        } else {
2182            tempDays = BigInteger.valueOf(startDay);
2183        }
2184        BigInteger endDays = tempDays.add(dDays).add(carry);
2185        int monthCarry;
2186        int intTemp;
2187        while (true) {
2188            if (endDays.compareTo(BigInteger.ONE) < 0) {
2189                // calculate days in previous month, watch for month roll over
2190                BigInteger mdimf = null;
2191                if (month >= 2) {
2192                    mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear(),
2193                            getMonth() - 1));
2194                } else {
2195                    // roll over to December of previous year
2196                    mdimf = BigInteger.valueOf(maximumDayInMonthFor(getEonAndYear()
2197                            .subtract(BigInteger.ONE), 12));
2198                }
2199                endDays = endDays.add(mdimf);
2200                monthCarry = -1;
2201            } else if (endDays.compareTo(BigInteger.valueOf(
2202                    maximumDayInMonthFor(getEonAndYear(), getMonth()))) > 0) {
2203                endDays = endDays.add(BigInteger.valueOf(
2204                        -maximumDayInMonthFor(getEonAndYear(), getMonth())));
2205                monthCarry = 1;
2206            } else {
2207                break;
2208            }
2209
2210            intTemp = getMonth() + monthCarry;
2211            int endMonth = (intTemp - 1) % (13 - 1);
2212            int quotient;
2213            if (endMonth < 0) {
2214                endMonth = (13 - 1) + endMonth + 1;
2215                quotient = BigDecimal.valueOf(intTemp - 1)
2216                        .divide(DECIMAL_TWELVE, RoundingMode.UP).intValue();
2217            } else {
2218                quotient = (intTemp - 1) / (13 - 1);
2219                endMonth += 1;
2220            }
2221            setMonth(endMonth);
2222            if (quotient != 0) {
2223                setYear(getEonAndYear().add(BigInteger.valueOf(quotient)));
2224            }
2225        }
2226        setDay(endDays.intValue());
2227
2228        // set fields that where undefined before this addition, back to undefined.
2229        for (int i = YEAR; i <= SECOND; i++) {
2230            if (fieldUndefined[i]) {
2231                switch (i) {
2232                case YEAR:
2233                    setYear(DatatypeConstants.FIELD_UNDEFINED);
2234                    break;
2235                case MONTH:
2236                    setMonth(DatatypeConstants.FIELD_UNDEFINED);
2237                    break;
2238                case DAY:
2239                    setDay(DatatypeConstants.FIELD_UNDEFINED);
2240                    break;
2241                case HOUR:
2242                    setHour(DatatypeConstants.FIELD_UNDEFINED, false);
2243                    break;
2244                case MINUTE:
2245                    setMinute(DatatypeConstants.FIELD_UNDEFINED);
2246                    break;
2247                case SECOND:
2248                    setSecond(DatatypeConstants.FIELD_UNDEFINED);
2249                    setFractionalSecond(null);
2250                    break;
2251                }
2252            }
2253        }
2254    }
2255
2256    private static final BigInteger FOUR = BigInteger.valueOf(4);
2257    private static final BigInteger HUNDRED = BigInteger.valueOf(100);
2258    private static final BigInteger FOUR_HUNDRED = BigInteger.valueOf(400);
2259    private static final BigInteger SIXTY = BigInteger.valueOf(60);
2260    private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24);
2261    private static final BigInteger TWELVE = BigInteger.valueOf(12);
2262    private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0);
2263    private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1);
2264    private static final BigDecimal DECIMAL_TWELVE = BigDecimal.valueOf(12);
2265    private static final BigDecimal DECIMAL_TWENTY_FOUR = BigDecimal.valueOf(24);
2266    private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60);
2267
2268
2269    private static class DaysInMonth {
2270        private static final int [] table = { 0,  // XML Schema months start at 1.
2271            31, 28, 31, 30, 31, 30,
2272            31, 31, 30, 31, 30, 31};
2273    }
2274
2275    private static int maximumDayInMonthFor(BigInteger year, int month) {
2276        if (month != DatatypeConstants.FEBRUARY) {
2277            return DaysInMonth.table[month];
2278        } else {
2279            if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) ||
2280                    (!year.mod(HUNDRED).equals(BigInteger.ZERO) &&
2281                            year.mod(FOUR).equals(BigInteger.ZERO))) {
2282                // is a leap year.
2283                return 29;
2284            } else {
2285                return DaysInMonth.table[month];
2286            }
2287        }
2288    }
2289
2290    private static int maximumDayInMonthFor(int year, int month) {
2291        if (month != DatatypeConstants.FEBRUARY) {
2292            return DaysInMonth.table[month];
2293        } else {
2294            if (((year % 400) == 0) ||
2295                    (((year % 100) != 0) && ((year % 4) == 0))) {
2296                // is a leap year.
2297                return 29;
2298            } else {
2299                return DaysInMonth.table[DatatypeConstants.FEBRUARY];
2300            }
2301        }
2302    }
2303
2304    /**
2305     * <p>Convert <code>this</code> to <code>java.util.GregorianCalendar</code>.</p>
2306     *
2307     * <p>When <code>this</code> instance has an undefined field, this
2308     * conversion relies on the <code>java.util.GregorianCalendar</code> default
2309     * for its corresponding field. A notable difference between
2310     * XML Schema 1.0 date/time datatypes and <code>java.util.GregorianCalendar</code>
2311     * is that Timezone value is optional for date/time datatypes and it is
2312     * a required field for <code>java.util.GregorianCalendar</code>. See javadoc
2313     * for <code>java.util.TimeZone.getDefault()</code> on how the default
2314     * is determined. To explicitly specify the <code>TimeZone</code>
2315     * instance, see
2316     * {@link #toGregorianCalendar(TimeZone, Locale, XMLGregorianCalendar)}.</p>
2317     *
2318     * <table border="2" rules="all" cellpadding="2">
2319     *   <thead>
2320     *     <tr>
2321     *       <th align="center" colspan="2">
2322     *          Field by Field Conversion from this class to
2323     *          <code>java.util.GregorianCalendar</code>
2324     *       </th>
2325     *     </tr>
2326     *   </thead>
2327     *   <tbody>
2328     *     <tr>
2329     *        <th><code>java.util.GregorianCalendar</code> field</th>
2330     *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
2331     *     </tr>
2332     *     <tr>
2333     *       <th><code>ERA</code></th>
2334     *       <th>{@link #getEonAndYear()}<code>.signum() < 0 ? GregorianCalendar.BC : GregorianCalendar.AD</code></th>
2335     *     </tr>
2336     *     <tr>
2337     *       <th><code>YEAR</code></th>
2338     *       <th>{@link #getEonAndYear()}<code>.abs().intValue()</code><i>*</i></th>
2339     *     </tr>
2340     *     <tr>
2341     *       <th><code>MONTH</code></th>
2342     *       <th>{@link #getMonth()}<code> - 1</code></th>
2343     *     </tr>
2344     *     <tr>
2345     *       <th><code>DAY_OF_MONTH</code></th>
2346     *       <th>{@link #getDay()}</th>
2347     *     </tr>
2348     *     <tr>
2349     *       <th><code>AM_PM</code></th>
2350     *       <th>{@link #getHour()} < 12 : Calendar.AM : Calendar.PM</th>
2351     *     </tr>
2352     *     <tr>
2353     *       <th><code>HOUR_OF_DAY</code></th>
2354     *       <th>{@link #getHour()}</th>
2355     *     </tr>
2356     *     <tr>
2357     *       <th><code>MINUTE</code></th>
2358     *       <th>{@link #getMinute()}</th>
2359     *     </tr>
2360     *     <tr>
2361     *       <th><code>SECOND</code></th>
2362     *       <th>{@link #getSecond()}</th>
2363     *     </tr>
2364     *     <tr>
2365     *       <th><code>MILLISECOND</code></th>
2366     *       <th>get millisecond order from {@link #getFractionalSecond()}<i>*</i> </th>
2367     *     </tr>
2368     *     <tr>
2369     *       <th><code>GregorianCalendar.setTimeZone(TimeZone)</code></th>
2370     *       <th>{@link #getTimezone()} formatted into Custom timezone id</th>
2371     *     </tr>
2372     *   </tbody>
2373     * </table>
2374     * <i>*</i> designates possible loss of precision during the conversion due
2375     * to source datatype having higer precison than target datatype.
2376     *
2377     * <p>To ensure consistency in conversion implementations, the new
2378     * <code>GregorianCalendar</code> should be instantiated in following
2379     * manner.
2380     * <ul>
2381     *   <li>Using <code>timeZone</code> value as defined above, create a new
2382     * <code>java.util.GregorianCalendar(timeZone,Locale.getDefault())</code>.
2383     *   </li>
2384     *   <li>Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.</li>
2385     *   <li>Obtain a pure Gregorian Calendar by invoking
2386     *   <code>GregorianCalendar.setGregorianChange(
2387     *   new Date(Long.MIN_VALUE))</code>.</li>
2388     *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
2389     *       MINUTE, SECOND and MILLISECOND are set using the method
2390     *       <code>Calendar.set(int,int)</code></li>
2391     * </ul>
2392     * </p>
2393     *
2394     * @see #toGregorianCalendar(java.util.TimeZone, java.util.Locale, XMLGregorianCalendar)
2395     */
2396    public java.util.GregorianCalendar toGregorianCalendar() {
2397
2398        GregorianCalendar result = null;
2399        final int DEFAULT_TIMEZONE_OFFSET = DatatypeConstants.FIELD_UNDEFINED;
2400        TimeZone tz = getTimeZone(DEFAULT_TIMEZONE_OFFSET);
2401        /** Use the following instead for JDK7 only:
2402         * Locale locale = Locale.getDefault(Locale.Category.FORMAT);
2403         */
2404        Locale locale = getDefaultLocale();
2405
2406        result = new GregorianCalendar(tz, locale);
2407        result.clear();
2408        result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2409
2410        // if year( and eon) are undefined, leave default Calendar values
2411        if (year != DatatypeConstants.FIELD_UNDEFINED) {
2412            if (eon == null) {
2413                result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2414                result.set(Calendar.YEAR, Math.abs(year));
2415            }
2416            else {
2417                BigInteger eonAndYear = getEonAndYear();
2418                result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2419                result.set(Calendar.YEAR, eonAndYear.abs().intValue());
2420            }
2421        }
2422
2423        // only set month if it is set
2424        if (month != DatatypeConstants.FIELD_UNDEFINED) {
2425            // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2426            result.set(Calendar.MONTH, month - 1);
2427        }
2428
2429        // only set day if it is set
2430        if (day != DatatypeConstants.FIELD_UNDEFINED) {
2431            result.set(Calendar.DAY_OF_MONTH, day);
2432        }
2433
2434        // only set hour if it is set
2435        if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2436            result.set(Calendar.HOUR_OF_DAY, hour);
2437        }
2438
2439        // only set minute if it is set
2440        if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2441            result.set(Calendar.MINUTE, minute);
2442        }
2443
2444        // only set second if it is set
2445        if (second != DatatypeConstants.FIELD_UNDEFINED) {
2446            result.set(Calendar.SECOND, second);
2447        }
2448
2449        // only set millisend if it is set
2450        if (fractionalSecond != null) {
2451            result.set(Calendar.MILLISECOND, getMillisecond());
2452        }
2453
2454        return result;
2455    }
2456
2457    /**
2458     *
2459     * @return default locale
2460     */
2461    private Locale getDefaultLocale() {
2462
2463        String lang = SecuritySupport.getSystemProperty("user.language.format");
2464        String country = SecuritySupport.getSystemProperty("user.country.format");
2465        String variant = SecuritySupport.getSystemProperty("user.variant.format");
2466        Locale locale = null;
2467        if (lang != null) {
2468            if (country != null) {
2469                if (variant != null) {
2470                    locale = new Locale(lang, country, variant);
2471                } else {
2472                    locale = new Locale(lang, country);
2473                }
2474            } else {
2475                locale = new Locale(lang);
2476            }
2477        }
2478        if (locale == null) {
2479            locale = Locale.getDefault();
2480        }
2481        return locale;
2482    }
2483
2484    /**
2485     * <p>Convert <code>this</code> along with provided parameters
2486     * to <code>java.util.GregorianCalendar</code> instance.</p>
2487     *
2488     * <p> Since XML Schema 1.0 date/time datetypes has no concept of
2489     * timezone ids or daylight savings timezone ids, this conversion operation
2490     * allows the user to explicitly specify one with
2491     * <code>timezone</code> parameter.</p>
2492     *
2493     * <p>To compute the return value's <code>TimeZone</code> field,
2494     * <ul>
2495     * <li>when parameter <code>timeZone</code> is non-null,
2496     * it is the timezone field.</li>
2497     * <li>else when <code>this.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
2498     * create a <code>java.util.TimeZone</code> with a custom timezone id
2499     * using the <code>this.getTimezone()</code>.</li>
2500     * <li>else when <code>defaults.getTimezone() != DatatypeConstants.FIELD_UNDEFINED</code>,
2501     * create a <code>java.util.TimeZone</code> with a custom timezone id
2502     * using <code>defaults.getTimezone()</code>.</li>
2503     * <li>else use the <code>GregorianCalendar</code> default timezone value
2504     * for the host is definedas specified by
2505     * <code>java.util.TimeZone.getDefault()</code>.</li></p>
2506     *
2507     * <p>To ensure consistency in conversion implementations, the new
2508     * <code>GregorianCalendar</code> should be instantiated in following
2509     * manner.
2510     * <ul>
2511     *   <li>Create a new <code>java.util.GregorianCalendar(TimeZone,
2512     *       Locale)</code> with TimeZone set as specified above and the
2513     *       <code>Locale</code> parameter.
2514     *   </li>
2515     *   <li>Initialize all GregorianCalendar fields by calling {(@link GegorianCalendar#clear()}.</li>
2516     *   <li>Obtain a pure Gregorian Calendar by invoking
2517     *   <code>GregorianCalendar.setGregorianChange(
2518     *   new Date(Long.MIN_VALUE))</code>.</li>
2519     *   <li>Its fields ERA, YEAR, MONTH, DAY_OF_MONTH, HOUR_OF_DAY,
2520     *       MINUTE, SECOND and MILLISECOND are set using the method
2521     *       <code>Calendar.set(int,int)</code></li>
2522     * </ul>
2523     *
2524     * @param timezone provide Timezone. <code>null</code> is a legal value.
2525     * @param aLocale  provide explicit Locale. Use default GregorianCalendar locale if
2526     *                 value is <code>null</code>.
2527     * @param defaults provide default field values to use when corresponding
2528     *                 field for this instance is DatatypeConstants.FIELD_UNDEFINED or null.
2529     *                 If <code>defaults</code>is <code>null</code> or a field
2530     *                 within the specified <code>defaults</code> is undefined,
2531     *                 just use <code>java.util.GregorianCalendar</code> defaults.
2532     * @return a java.util.GregorianCalendar conversion of this instance.
2533     *
2534     * @see #LEAP_YEAR_DEFAULT
2535     */
2536    public GregorianCalendar toGregorianCalendar(TimeZone timezone,
2537                                                 Locale aLocale,
2538                                                 XMLGregorianCalendar defaults) {
2539        GregorianCalendar result = null;
2540        TimeZone tz = timezone;
2541        if (tz == null) {
2542            int defaultZoneoffset = DatatypeConstants.FIELD_UNDEFINED;
2543            if (defaults != null) {
2544                defaultZoneoffset = defaults.getTimezone();
2545            }
2546            tz = getTimeZone(defaultZoneoffset);
2547        }
2548        if (aLocale == null) {
2549            aLocale = Locale.getDefault();
2550        }
2551        result = new GregorianCalendar(tz, aLocale);
2552        result.clear();
2553        result.setGregorianChange(PURE_GREGORIAN_CHANGE);
2554
2555        // if year( and eon) are undefined, leave default Calendar values
2556        if (year != DatatypeConstants.FIELD_UNDEFINED) {
2557            if (eon == null) {
2558                result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2559                result.set(Calendar.YEAR, Math.abs(year));
2560            }
2561            else {
2562                final BigInteger eonAndYear = getEonAndYear();
2563                result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2564                result.set(Calendar.YEAR, eonAndYear.abs().intValue());
2565            }
2566        } else {
2567            // use default if set
2568            if (defaults != null) {
2569                final int defaultYear = defaults.getYear();
2570                if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) {
2571                    if (defaults.getEon() == null) {
2572                        result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
2573                        result.set(Calendar.YEAR, Math.abs(defaultYear));
2574                    }
2575                    else {
2576                        final BigInteger defaultEonAndYear = defaults.getEonAndYear();
2577                        result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
2578                        result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue());
2579                    }
2580                }
2581            }
2582        }
2583
2584        // only set month if it is set
2585        if (month != DatatypeConstants.FIELD_UNDEFINED) {
2586            // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2587            result.set(Calendar.MONTH, month - 1);
2588        } else {
2589            // use default if set
2590            final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
2591            if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) {
2592                // Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
2593                result.set(Calendar.MONTH, defaultMonth - 1);
2594            }
2595        }
2596
2597        // only set day if it is set
2598        if (day != DatatypeConstants.FIELD_UNDEFINED) {
2599            result.set(Calendar.DAY_OF_MONTH, day);
2600        } else {
2601            // use default if set
2602            final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
2603            if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) {
2604                result.set(Calendar.DAY_OF_MONTH, defaultDay);
2605            }
2606        }
2607
2608        // only set hour if it is set
2609        if (hour != DatatypeConstants.FIELD_UNDEFINED) {
2610            result.set(Calendar.HOUR_OF_DAY, hour);
2611        } else {
2612            // use default if set
2613            int defaultHour = (defaults != null) ? defaults.getHour() : DatatypeConstants.FIELD_UNDEFINED;
2614            if (defaultHour != DatatypeConstants.FIELD_UNDEFINED) {
2615                result.set(Calendar.HOUR_OF_DAY, defaultHour);
2616            }
2617        }
2618
2619        // only set minute if it is set
2620        if (minute != DatatypeConstants.FIELD_UNDEFINED) {
2621            result.set(Calendar.MINUTE, minute);
2622        } else {
2623            // use default if set
2624            final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
2625            if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) {
2626                result.set(Calendar.MINUTE, defaultMinute);
2627            }
2628        }
2629
2630        // only set second if it is set
2631        if (second != DatatypeConstants.FIELD_UNDEFINED) {
2632            result.set(Calendar.SECOND, second);
2633        } else {
2634            // use default if set
2635            final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
2636            if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) {
2637                result.set(Calendar.SECOND, defaultSecond);
2638            }
2639        }
2640
2641        // only set millisend if it is set
2642        if (fractionalSecond != null) {
2643            result.set(Calendar.MILLISECOND, getMillisecond());
2644        } else {
2645            // use default if set
2646            final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
2647            if (defaultFractionalSecond != null) {
2648                result.set(Calendar.MILLISECOND, defaults.getMillisecond());
2649            }
2650        }
2651
2652        return result;
2653    }
2654
2655    /**
2656     * <p>Returns a <code>java.util.TimeZone</code> for this class.</p>
2657     *
2658     * <p>If timezone field is defined for this instance,
2659     * returns TimeZone initialized with custom timezone id
2660     * of zoneoffset. If timezone field is undefined,
2661     * try the defaultZoneoffset that was passed in.
2662     * If defaultZoneoffset is DatatypeConstants.FIELD_UNDEFINED, return
2663     * default timezone for this host.
2664     * (Same default as java.util.GregorianCalendar).</p>
2665     *
2666     * @param defaultZoneoffset default zoneoffset if this zoneoffset is
2667     * {@link DatatypeConstants#FIELD_UNDEFINED}.
2668     *
2669     * @return TimeZone for this.
2670     */
2671    public TimeZone getTimeZone(int defaultZoneoffset) {
2672        TimeZone result = null;
2673        int zoneoffset = getTimezone();
2674
2675        if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) {
2676            zoneoffset = defaultZoneoffset;
2677        }
2678        if (zoneoffset == DatatypeConstants.FIELD_UNDEFINED) {
2679            result = TimeZone.getDefault();
2680        } else {
2681            // zoneoffset is in minutes. Convert to custom timezone id format.
2682            char sign = zoneoffset < 0 ? '-' : '+';
2683            if (sign == '-') {
2684                zoneoffset = -zoneoffset;
2685            }
2686            int hour = zoneoffset / 60;
2687            int minutes = zoneoffset - (hour * 60);
2688
2689            // Javadoc for java.util.TimeZone documents max length
2690            // for customTimezoneId is 8 when optional ':' is not used.
2691            // Format is
2692            // "GMT" ('-'|''+') (digit digit?) (digit digit)?
2693            //                   hour          minutes
2694            StringBuffer customTimezoneId = new StringBuffer(8);
2695            customTimezoneId.append("GMT");
2696            customTimezoneId.append(sign);
2697            customTimezoneId.append(hour);
2698            if (minutes != 0) {
2699                if (minutes < 10) {
2700                    customTimezoneId.append('0');
2701                }
2702                customTimezoneId.append(minutes);
2703            }
2704            result = TimeZone.getTimeZone(customTimezoneId.toString());
2705        }
2706        return result;
2707    }
2708
2709    /**
2710     * <p>Creates and returns a copy of this object.</p>
2711     *
2712     * @return copy of this <code>Object</code>
2713     */
2714   public Object clone() {
2715        // Both this.eon and this.fractionalSecond are instances
2716        // of immutable classes, so they do not need to be cloned.
2717       return new XMLGregorianCalendarImpl(getEonAndYear(),
2718                        this.month, this.day,
2719                        this.hour, this.minute, this.second,
2720                        this.fractionalSecond,
2721                        this.timezone);
2722    }
2723
2724    /**
2725     * <p>Unset all fields to undefined.</p>
2726     *
2727     * <p>Set all int fields to {@link DatatypeConstants#FIELD_UNDEFINED} and reference fields
2728     * to null.</p>
2729     */
2730    public void clear() {
2731        eon = null;
2732        year = DatatypeConstants.FIELD_UNDEFINED;
2733        month = DatatypeConstants.FIELD_UNDEFINED;
2734        day = DatatypeConstants.FIELD_UNDEFINED;
2735        timezone = DatatypeConstants.FIELD_UNDEFINED;  // in minutes
2736        hour = DatatypeConstants.FIELD_UNDEFINED;
2737        minute = DatatypeConstants.FIELD_UNDEFINED;
2738        second = DatatypeConstants.FIELD_UNDEFINED;
2739        fractionalSecond = null;
2740    }
2741
2742    public void setMillisecond(int millisecond) {
2743        if (millisecond == DatatypeConstants.FIELD_UNDEFINED) {
2744            fractionalSecond = null;
2745        } else {
2746            if(millisecond<0 || 999<millisecond)
2747                if(millisecond!=DatatypeConstants.FIELD_UNDEFINED)
2748                    invalidFieldValue(MILLISECOND, millisecond);
2749            fractionalSecond = BigDecimal.valueOf(millisecond, 3);
2750        }
2751    }
2752
2753    public final void setFractionalSecond(BigDecimal fractional) {
2754        if (fractional != null) {
2755            if ((fractional.compareTo(DECIMAL_ZERO) < 0) ||
2756                    (fractional.compareTo(DECIMAL_ONE) > 0)) {
2757                throw new IllegalArgumentException(DatatypeMessageFormatter.formatMessage(null,
2758                        "InvalidFractional", new Object[]{fractional}));
2759            }
2760        }
2761        this.fractionalSecond = fractional;
2762    }
2763
2764    private final class Parser {
2765        private final String format;
2766        private final String value;
2767
2768        private final int flen;
2769        private final int vlen;
2770
2771        private int fidx;
2772        private int vidx;
2773
2774        private Parser(String format, String value) {
2775            this.format = format;
2776            this.value = value;
2777            this.flen = format.length();
2778            this.vlen = value.length();
2779        }
2780
2781        /**
2782         * <p>Parse a formated <code>String</code> into an <code>XMLGregorianCalendar</code>.</p>
2783         *
2784         * <p>If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value,
2785         * an <code>IllegalArgumentException</code> is thrown.</p>
2786         *
2787         * @throws IllegalArgumentException If <code>String</code> is not formated as a legal <code>XMLGregorianCalendar</code> value.
2788         */
2789        public void parse() throws IllegalArgumentException {
2790            while (fidx < flen) {
2791                char fch = format.charAt(fidx++);
2792
2793                if (fch != '%') { // not a meta character
2794                    skip(fch);
2795                    continue;
2796                }
2797
2798                // seen meta character. we don't do error check against the format
2799                switch (format.charAt(fidx++)) {
2800                    case 'Y' : // year
2801                        parseYear();
2802                        break;
2803
2804                    case 'M' : // month
2805                        setMonth(parseInt(2, 2));
2806                        break;
2807
2808                    case 'D' : // days
2809                        setDay(parseInt(2, 2));
2810                        break;
2811
2812                    case 'h' : // hours
2813                        setHour(parseInt(2, 2), false);
2814                        break;
2815
2816                    case 'm' : // minutes
2817                        setMinute(parseInt(2, 2));
2818                        break;
2819
2820                    case 's' : // parse seconds.
2821                        setSecond(parseInt(2, 2));
2822
2823                        if (peek() == '.') {
2824                            setFractionalSecond(parseBigDecimal());
2825                        }
2826                        break;
2827
2828                    case 'z' : // time zone. missing, 'Z', or [+-]nn:nn
2829                        char vch = peek();
2830                        if (vch == 'Z') {
2831                            vidx++;
2832                            setTimezone(0);
2833                        } else if (vch == '+' || vch == '-') {
2834                            vidx++;
2835                            int h = parseInt(2, 2);
2836                            skip(':');
2837                            int m = parseInt(2, 2);
2838                            setTimezone((h * 60 + m) * (vch == '+' ? 1 : -1));
2839                        }
2840
2841                        break;
2842
2843                    default :
2844                        // illegal meta character. impossible.
2845                        throw new InternalError();
2846                }
2847            }
2848
2849            if (vidx != vlen) {
2850                // some tokens are left in the input
2851                throw new IllegalArgumentException(value); //,vidx);
2852            }
2853            testHour();
2854        }
2855
2856        private char peek() throws IllegalArgumentException {
2857            if (vidx == vlen) {
2858                return (char) -1;
2859            }
2860            return value.charAt(vidx);
2861        }
2862
2863        private char read() throws IllegalArgumentException {
2864            if (vidx == vlen) {
2865                throw new IllegalArgumentException(value); //,vidx);
2866            }
2867            return value.charAt(vidx++);
2868        }
2869
2870        private void skip(char ch) throws IllegalArgumentException {
2871            if (read() != ch) {
2872                throw new IllegalArgumentException(value); //,vidx-1);
2873            }
2874        }
2875
2876        private int parseInt(int minDigits, int maxDigits)
2877            throws IllegalArgumentException {
2878
2879            int n = 0;
2880            char ch;
2881            int vstart = vidx;
2882            while (isDigit(ch=peek()) && (vidx - vstart) < maxDigits) {
2883                vidx++;
2884                n = n*10 + ch-'0';
2885            }
2886            if ((vidx - vstart) < minDigits) {
2887                // we are expecting more digits
2888                throw new IllegalArgumentException(value); //,vidx);
2889            }
2890
2891            return n;
2892        }
2893
2894        private void parseYear()
2895            throws IllegalArgumentException {
2896            int vstart = vidx;
2897            int sign = 0;
2898
2899            // skip leading negative, if it exists
2900            if (peek() == '-') {
2901                vidx++;
2902                sign = 1;
2903            }
2904            while (isDigit(peek())) {
2905                vidx++;
2906            }
2907            final int digits = vidx - vstart - sign;
2908            if (digits < 4) {
2909                // we are expecting more digits
2910                throw new IllegalArgumentException(value); //,vidx);
2911            }
2912            final String yearString = value.substring(vstart, vidx);
2913            if (digits < 10) {
2914                setYear(Integer.parseInt(yearString));
2915            }
2916            else {
2917                setYear(new BigInteger(yearString));
2918            }
2919        }
2920
2921        private BigDecimal parseBigDecimal()
2922                throws IllegalArgumentException {
2923            int vstart = vidx;
2924
2925            if (peek() == '.') {
2926                vidx++;
2927            } else {
2928                throw new IllegalArgumentException(value);
2929            }
2930            while (isDigit(peek())) {
2931                vidx++;
2932            }
2933            return new BigDecimal(value.substring(vstart, vidx));
2934        }
2935    }
2936
2937    private static boolean isDigit(char ch) {
2938        return '0' <= ch && ch <= '9';
2939    }
2940
2941    /**
2942     * Prints this object according to the format specification.
2943     *
2944     * <p>
2945     * StringBuffer -> StringBuilder change had a very visible impact.
2946     * It almost cut the execution time to half.
2947     * Diff from Xerces:
2948     * Xerces use StringBuffer due to the requirement to support
2949     * JDKs older than JDK 1.5
2950     */
2951    private String format( String format ) {
2952        StringBuilder buf = new StringBuilder();
2953        int fidx=0,flen=format.length();
2954
2955        while(fidx<flen) {
2956            char fch = format.charAt(fidx++);
2957            if(fch!='%') {// not a meta char
2958                buf.append(fch);
2959                continue;
2960            }
2961
2962            switch(format.charAt(fidx++)) {
2963                case 'Y':
2964                    if (eon == null) {
2965                        int absYear = year;
2966                        if (absYear < 0) {
2967                            buf.append('-');
2968                            absYear = -year;
2969                        }
2970                        printNumber(buf, absYear, 4);
2971                    }
2972                    else {
2973                        printNumber(buf, getEonAndYear(), 4);
2974                    }
2975                    break;
2976                case 'M':
2977                    printNumber(buf,getMonth(),2);
2978                    break;
2979                case 'D':
2980                    printNumber(buf,getDay(),2);
2981                    break;
2982                case 'h':
2983                    printNumber(buf,getHour(),2);
2984                    break;
2985                case 'm':
2986                    printNumber(buf,getMinute(),2);
2987                    break;
2988                case 's':
2989                    printNumber(buf,getSecond(),2);
2990                    if (getFractionalSecond() != null) {
2991                        //Xerces uses a custom method toString instead of
2992                        //toPlainString() since it needs to support JDKs older than 1.5
2993                        String frac = getFractionalSecond().toPlainString();
2994                        //skip leading zero.
2995                        buf.append(frac.substring(1, frac.length()));
2996                    }
2997                    break;
2998                case 'z':
2999                    int offset = getTimezone();
3000                    if (offset == 0) {
3001                        buf.append('Z');
3002                    }
3003                    else if (offset != DatatypeConstants.FIELD_UNDEFINED) {
3004                        if (offset < 0) {
3005                            buf.append('-');
3006                            offset *= -1;
3007                        }
3008                        else {
3009                            buf.append('+');
3010                        }
3011                        printNumber(buf,offset/60,2);
3012                        buf.append(':');
3013                        printNumber(buf,offset%60,2);
3014                    }
3015                    break;
3016                default:
3017                    throw new InternalError();  // impossible
3018            }
3019        }
3020
3021        return buf.toString();
3022    }
3023
3024    /**
3025     * Prints an integer as a String.
3026     *
3027     * @param out
3028     *      The formatted string will be appended into this buffer.
3029     * @param number
3030     *      The integer to be printed.
3031     * @param nDigits
3032     *      The field will be printed by using at least this
3033     *      number of digits. For example, 5 will be printed as "0005"
3034     *      if nDigits==4.
3035     */
3036    private void printNumber( StringBuilder out, int number, int nDigits ) {
3037        String s = String.valueOf(number);
3038        for (int i = s.length(); i < nDigits; i++) {
3039            out.append('0');
3040        }
3041        out.append(s);
3042    }
3043
3044    /**
3045     * Prints an BigInteger as a String.
3046     *
3047     * @param out
3048     *      The formatted string will be appended into this buffer.
3049     * @param number
3050     *      The integer to be printed.
3051     * @param nDigits
3052     *      The field will be printed by using at least this
3053     *      number of digits. For example, 5 will be printed as "0005"
3054     *      if nDigits==4.
3055     */
3056    private void printNumber( StringBuilder out, BigInteger number, int nDigits) {
3057        String s = number.toString();
3058        for (int i=s.length(); i < nDigits; i++) {
3059            out.append('0');
3060        }
3061        out.append(s);
3062    }
3063
3064    /**
3065     * Compute <code>value*signum</code> where value==null is treated as
3066     * value==0.
3067     * @return non-null {@link BigInteger}.
3068     */
3069    static BigInteger sanitize(Number value, int signum) {
3070        if (signum == 0 || value == null) {
3071            return BigInteger.ZERO;
3072        }
3073        return (signum <  0)? ((BigInteger)value).negate() : (BigInteger)value;
3074    }
3075
3076    /** <p><code>reset()</code> is designed to allow the reuse of existing
3077     * <code>XMLGregorianCalendar</code>s thus saving resources associated
3078     *  with the creation of new <code>XMLGregorianCalendar</code>s.</p>
3079     */
3080    public void reset() {
3081        eon = orig_eon;
3082        year = orig_year;
3083        month = orig_month;
3084        day = orig_day;
3085        hour = orig_hour;
3086        minute = orig_minute;
3087        second = orig_second;
3088        fractionalSecond = orig_fracSeconds;
3089        timezone = orig_timezone;
3090    }
3091
3092    /** Deserialize Calendar. */
3093    private void readObject(ObjectInputStream ois)
3094        throws ClassNotFoundException, IOException {
3095
3096        // perform default deseralization
3097        ois.defaultReadObject();
3098
3099        // initialize orig_* fields
3100        save();
3101
3102    } // readObject(ObjectInputStream)
3103}
3104