Home | History | Annotate | Download | only in datatype
      1 /*
      2  * Licensed to the Apache Software Foundation (ASF) under one or more
      3  * contributor license agreements.  See the NOTICE file distributed with
      4  * this work for additional information regarding copyright ownership.
      5  * The ASF licenses this file to You under the Apache License, Version 2.0
      6  * (the "License"); you may not use this file except in compliance with
      7  * the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 //$Id: DatatypeFactory.java 884950 2009-11-27 18:46:18Z mrglavas $
     19 
     20 package javax.xml.datatype;
     21 
     22 import java.math.BigDecimal;
     23 import java.math.BigInteger;
     24 import java.util.GregorianCalendar;
     25 
     26 /**
     27  * <p>Factory that creates new <code>javax.xml.datatype</code> <code>Object</code>s that map XML to/from Java <code>Object</code>s.</p>
     28  *
     29  * <p id="DatatypeFactory.newInstance">{@link #newInstance()} is used to create a new <code>DatatypeFactory</code>.
     30  * The following implementation resolution mechanisms are used in the following order:</p>
     31  * <ol>
     32  *    <li>
     33  *      If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "<code>javax.xml.datatype.DatatypeFactory</code>",
     34  *      exists, a class with the name of the property's value is instantiated.
     35  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
     36  *    </li>
     37  *    <li>
     38  *      If the file ${JAVA_HOME}/lib/jaxp.properties exists, it is loaded in a {@link java.util.Properties} <code>Object</code>.
     39  *      The <code>Properties</code> <code>Object </code> is then queried for the property as documented in the prior step
     40  *      and processed as documented in the prior step.
     41  *    </li>
     42  *    <li>
     43  *      The services resolution mechanism is used, e.g. <code>META-INF/services/java.xml.datatype.DatatypeFactory</code>.
     44  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
     45  *    </li>
     46  *    <li>
     47  *      The final mechanism is to attempt to instantiate the <code>Class</code> specified by
     48  *      {@link #DATATYPEFACTORY_IMPLEMENTATION_CLASS}, "<code>javax.xml.datatype.DatatypeFactoryImpl</code>".
     49  *      Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}.
     50  *    </li>
     51  * </ol>
     52  *
     53  * <p>Note that you must supply your own implementation (such as Xerces); Android does not ship with a default implementation.
     54  *
     55  * @author <a href="mailto:Joseph.Fialli (at) Sun.COM">Joseph Fialli</a>
     56  * @author <a href="mailto:Jeff.Suttor (at) Sun.com">Jeff Suttor</a>
     57  * @version $Revision: 884950 $, $Date: 2009-11-27 10:46:18 -0800 (Fri, 27 Nov 2009) $
     58  * @since 1.5
     59  */
     60 public abstract class DatatypeFactory {
     61 
     62     /**
     63      * <p>Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
     64      *
     65      * <p>Default value is <code>javax.xml.datatype.DatatypeFactory</code>.</p>
     66      */
     67     public static final String DATATYPEFACTORY_PROPERTY = "javax.xml.datatype.DatatypeFactory";
     68 
     69     /**
     70      * <p>Default implementation class name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3.</p>
     71      *
     72      * <p>Default value is <code>org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl</code>.</p>
     73      */
     74     // This uses "new String" to avoid being inlined as a constant.
     75     public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = new String("org.apache.xerces.jaxp.datatype.DatatypeFactoryImpl");
     76 
     77     /**
     78      * <p>Protected constructor to prevent instantiation outside of package.</p>
     79      *
     80      * <p>Use {@link #newInstance()} to create a <code>DatatypeFactory</code>.</p>
     81      */
     82     protected DatatypeFactory() {}
     83 
     84     /**
     85      * <p>Obtain a new instance of a <code>DatatypeFactory</code>.</p>
     86      *
     87      * <p>The implementation resolution mechanisms are <a href="#DatatypeFactory.newInstance">defined</a> in this
     88      * <code>Class</code>'s documentation.</p>
     89      * <p>Note that you must supply your own implementation (such as Xerces); Android does not ship with a default implementation.
     90      *
     91      * @return New instance of a <code>DocumentBuilderFactory</code>
     92      *
     93      * @throws DatatypeConfigurationException If the implementation is not
     94      *   available or cannot be instantiated.
     95      */
     96     public static DatatypeFactory newInstance()
     97         throws DatatypeConfigurationException {
     98         try {
     99             return (DatatypeFactory) FactoryFinder.find(
    100                     /* The default property name according to the JAXP spec */
    101                     DATATYPEFACTORY_PROPERTY,
    102                     /* The fallback implementation class name */
    103                     DATATYPEFACTORY_IMPLEMENTATION_CLASS);
    104         }
    105         catch (FactoryFinder.ConfigurationError e) {
    106             throw new DatatypeConfigurationException(e.getMessage(), e.getException());
    107         }
    108     }
    109 
    110     /**
    111      * Returns an instance of the named implementation of {@code DatatypeFactory}.
    112      *
    113      * @throws DatatypeConfigurationException if {@code factoryClassName} is not available or cannot
    114      *     be instantiated.
    115      * @since 1.6
    116      */
    117     public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader)
    118             throws DatatypeConfigurationException {
    119         if (factoryClassName == null) {
    120             throw new DatatypeConfigurationException("factoryClassName == null");
    121         }
    122         if (classLoader == null) {
    123             classLoader = Thread.currentThread().getContextClassLoader();
    124         }
    125         try {
    126             Class<?> type = classLoader != null
    127                     ? classLoader.loadClass(factoryClassName)
    128                     : Class.forName(factoryClassName);
    129             return (DatatypeFactory) type.newInstance();
    130         } catch (ClassNotFoundException e) {
    131             throw new DatatypeConfigurationException(e);
    132         } catch (InstantiationException e) {
    133             throw new DatatypeConfigurationException(e);
    134         } catch (IllegalAccessException e) {
    135             throw new DatatypeConfigurationException(e);
    136         }
    137     }
    138 
    139     /**
    140      * <p>Obtain a new instance of a <code>Duration</code>
    141      * specifying the <code>Duration</code> as its string representation, "PnYnMnDTnHnMnS",
    142      * as defined in XML Schema 1.0 section 3.2.6.1.</p>
    143      *
    144      * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
    145      * <blockquote>
    146      * duration represents a duration of time.
    147      * The value space of duration is a six-dimensional space where the coordinates designate the
    148      * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
    149      * These components are ordered in their significance by their order of appearance i.e. as
    150      * year, month, day, hour, minute, and second.
    151      * </blockquote>
    152      * <p>All six values are set and available from the created {@link Duration}</p>
    153      *
    154      * <p>The XML Schema specification states that values can be of an arbitrary size.
    155      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    156      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    157      * if implementation capacities are exceeded.</p>
    158      *
    159      * @param lexicalRepresentation <code>String</code> representation of a <code>Duration</code>.
    160      *
    161      * @return New <code>Duration</code> created from parsing the <code>lexicalRepresentation</code>.
    162      *
    163      * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code>.
    164      * @throws UnsupportedOperationException If implementation cannot support requested values.
    165      * @throws NullPointerException if <code>lexicalRepresentation</code> is <code>null</code>.
    166      */
    167     public abstract Duration newDuration(final String lexicalRepresentation);
    168 
    169     /**
    170      * <p>Obtain a new instance of a <code>Duration</code>
    171      * specifying the <code>Duration</code> as milliseconds.</p>
    172      *
    173      * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines <code>duration</code> as:</p>
    174      * <blockquote>
    175      * duration represents a duration of time.
    176      * The value space of duration is a six-dimensional space where the coordinates designate the
    177      * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively.
    178      * These components are ordered in their significance by their order of appearance i.e. as
    179      * year, month, day, hour, minute, and second.
    180      * </blockquote>
    181      * <p>All six values are set by computing their values from the specified milliseconds
    182      * and are available using the <code>get</code> methods of  the created {@link Duration}.
    183      * The values conform to and are defined by:</p>
    184      * <ul>
    185      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
    186      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
    187      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
    188      *   </li>
    189      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
    190      * </ul>
    191      *
    192      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
    193      * {@link java.util.Calendar#YEAR} = 1970,
    194      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
    195      * {@link java.util.Calendar#DATE} = 1, etc.
    196      * This is important as there are variations in the Gregorian Calendar,
    197      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
    198      * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced.</p>
    199      *
    200      * @param durationInMilliSeconds Duration in milliseconds to create.
    201      *
    202      * @return New <code>Duration</code> representing <code>durationInMilliSeconds</code>.
    203      */
    204     public abstract Duration newDuration(final long durationInMilliSeconds);
    205 
    206     /**
    207      * <p>Obtain a new instance of a <code>Duration</code>
    208      * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
    209      *
    210      * <p>The XML Schema specification states that values can be of an arbitrary size.
    211      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    212      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    213      * if implementation capacities are exceeded.</p>
    214      *
    215      * <p>A <code>null</code> value indicates that field is not set.</p>
    216      *
    217      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    218      *   of the duration is zero, this parameter will be ignored.
    219      * @param years of this <code>Duration</code>
    220      * @param months of this <code>Duration</code>
    221      * @param days of this <code>Duration</code>
    222      * @param hours of this <code>Duration</code>
    223      * @param minutes of this <code>Duration</code>
    224      * @param seconds of this <code>Duration</code>
    225      *
    226      * @return New <code>Duration</code> created from the specified values.
    227      *
    228      * @throws IllegalArgumentException If values are not a valid representation of a <code>Duration</code>.
    229      * @throws UnsupportedOperationException If implementation cannot support requested values.
    230      */
    231     public abstract Duration newDuration(
    232             final boolean isPositive,
    233             final BigInteger years,
    234             final BigInteger months,
    235             final BigInteger days,
    236             final BigInteger hours,
    237             final BigInteger minutes,
    238             final BigDecimal seconds);
    239 
    240     /**
    241      * <p>Obtain a new instance of a <code>Duration</code>
    242      * specifying the <code>Duration</code> as isPositive, years, months, days, hours, minutes, seconds.</p>
    243      *
    244      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    245      *
    246      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    247      *   of the duration is zero, this parameter will be ignored.
    248      * @param years of this <code>Duration</code>
    249      * @param months of this <code>Duration</code>
    250      * @param days of this <code>Duration</code>
    251      * @param hours of this <code>Duration</code>
    252      * @param minutes of this <code>Duration</code>
    253      * @param seconds of this <code>Duration</code>
    254      *
    255      * @return New <code>Duration</code> created from the specified values.
    256      *
    257      * @throws IllegalArgumentException If values are not a valid representation of a <code>Duration</code>.
    258      *
    259      * @see #newDuration(
    260      *   boolean isPositive,
    261      *   BigInteger years,
    262      *   BigInteger months,
    263      *   BigInteger days,
    264      *   BigInteger hours,
    265      *   BigInteger minutes,
    266      *   BigDecimal seconds)
    267      */
    268     public Duration newDuration(
    269             final boolean isPositive,
    270             final int years,
    271             final int months,
    272             final int days,
    273             final int hours,
    274             final int minutes,
    275             final int seconds) {
    276 
    277         // years may not be set
    278         BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null;
    279 
    280         // months may not be set
    281         BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null;
    282 
    283         // days may not be set
    284         BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null;
    285 
    286         // hours may not be set
    287         BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null;
    288 
    289         // minutes may not be set
    290         BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null;
    291 
    292         // seconds may not be set
    293         BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null;
    294 
    295         return newDuration(
    296                 isPositive,
    297                 realYears,
    298                 realMonths,
    299                 realDays,
    300                 realHours,
    301                 realMinutes,
    302                 realSeconds
    303         );
    304     }
    305 
    306     /**
    307      * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> by parsing its <code>String</code> representation,
    308      * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
    309      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
    310      *
    311      * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
    312      * whose lexical representation contains only day, hour, minute, and second components.
    313      * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
    314      *
    315      * <p>All four values are set and available from the created {@link Duration}</p>
    316      *
    317      * <p>The XML Schema specification states that values can be of an arbitrary size.
    318      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    319      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    320      * if implementation capacities are exceeded.</p>
    321      *
    322      * @param lexicalRepresentation Lexical representation of a duration.
    323      *
    324      * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
    325      *
    326      * @throws IllegalArgumentException If the given string does not conform to the aforementioned specification.
    327      * @throws UnsupportedOperationException If implementation cannot support requested values.
    328      * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
    329      */
    330     public Duration newDurationDayTime(final String lexicalRepresentation) {
    331         if (lexicalRepresentation == null) {
    332             throw new NullPointerException("lexicalRepresentation == null");
    333         }
    334         // The lexical representation must match the pattern [^YM]*(T.*)?
    335         int pos = lexicalRepresentation.indexOf('T');
    336         int length = (pos >= 0) ? pos : lexicalRepresentation.length();
    337         for (int i = 0; i < length; ++i) {
    338             char c = lexicalRepresentation.charAt(i);
    339             if (c == 'Y' || c == 'M') {
    340                 throw new IllegalArgumentException("Invalid dayTimeDuration value: " + lexicalRepresentation);
    341             }
    342         }
    343         return newDuration(lexicalRepresentation);
    344     }
    345 
    346     /**
    347      * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified milliseconds as defined in
    348      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
    349      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
    350      *
    351      * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
    352      * whose lexical representation contains only day, hour, minute, and second components.
    353      * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
    354      *
    355      * <p>All four values are set by computing their values from the specified milliseconds
    356      * and are available using the <code>get</code> methods of  the created {@link Duration}.
    357      * The values conform to and are defined by:</p>
    358      * <ul>
    359      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
    360      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
    361      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
    362      *   </li>
    363      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
    364      * </ul>
    365      *
    366      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
    367      * {@link java.util.Calendar#YEAR} = 1970,
    368      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
    369      * {@link java.util.Calendar#DATE} = 1, etc.
    370      * This is important as there are variations in the Gregorian Calendar,
    371      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
    372      * so the result of {@link Duration#getDays()} can be influenced.</p>
    373      *
    374      * <p>Any remaining milliseconds after determining the day, hour, minute and second are discarded.</p>
    375      *
    376      * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
    377      *
    378      * @return New <code>Duration</code> created with the specified <code>durationInMilliseconds</code>.
    379      *
    380      * @see <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
    381      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>
    382      */
    383     public Duration newDurationDayTime(final long durationInMilliseconds) {
    384         long _durationInMilliseconds = durationInMilliseconds;
    385         if (_durationInMilliseconds == 0) {
    386             return newDuration(true, DatatypeConstants.FIELD_UNDEFINED,
    387                     DatatypeConstants.FIELD_UNDEFINED, 0, 0, 0, 0);
    388         }
    389         boolean tooLong = false;
    390         final boolean isPositive;
    391         if (_durationInMilliseconds < 0) {
    392             isPositive = false;
    393             if (_durationInMilliseconds == Long.MIN_VALUE) {
    394                 _durationInMilliseconds++;
    395                 tooLong = true;
    396             }
    397             _durationInMilliseconds *= -1;
    398         }
    399         else {
    400             isPositive = true;
    401         }
    402 
    403         long val = _durationInMilliseconds;
    404         int milliseconds = (int) (val % 60000L); // 60000 milliseconds per minute
    405         if (tooLong) {
    406             ++milliseconds;
    407         }
    408         if (milliseconds % 1000 == 0) {
    409             int seconds = milliseconds / 1000;
    410             val = val / 60000L;
    411             int minutes = (int) (val % 60L); // 60 minutes per hour
    412             val = val / 60L;
    413             int hours = (int) (val % 24L); // 24 hours per day
    414             long days = val / 24L;
    415             if (days <= ((long) Integer.MAX_VALUE)) {
    416                 return newDuration(isPositive, DatatypeConstants.FIELD_UNDEFINED,
    417                         DatatypeConstants.FIELD_UNDEFINED, (int) days, hours, minutes, seconds);
    418             }
    419             else {
    420                 return newDuration(isPositive, null, null,
    421                         BigInteger.valueOf(days), BigInteger.valueOf(hours),
    422                         BigInteger.valueOf(minutes), BigDecimal.valueOf(milliseconds, 3));
    423             }
    424         }
    425 
    426         BigDecimal seconds = BigDecimal.valueOf(milliseconds, 3);
    427         val = val / 60000L;
    428         BigInteger minutes = BigInteger.valueOf(val % 60L); // 60 minutes per hour
    429         val = val / 60L;
    430         BigInteger hours = BigInteger.valueOf(val % 24L); // 24 hours per day
    431         val = val / 24L;
    432         BigInteger days = BigInteger.valueOf(val);
    433         return newDuration(isPositive, null, null, days, hours, minutes, seconds);
    434     }
    435 
    436     /**
    437      * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
    438      * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
    439      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
    440      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
    441      *
    442      * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
    443      * whose lexical representation contains only day, hour, minute, and second components.
    444      * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
    445      *
    446      * <p>The XML Schema specification states that values can be of an arbitrary size.
    447      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    448      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    449      * if implementation capacities are exceeded.</p>
    450      *
    451      * <p>A <code>null</code> value indicates that field is not set.</p>
    452      *
    453      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    454      *   of the duration is zero, this parameter will be ignored.
    455      * @param day Day of <code>Duration</code>.
    456      * @param hour Hour of <code>Duration</code>.
    457      * @param minute Minute of <code>Duration</code>.
    458      * @param second Second of <code>Duration</code>.
    459      *
    460      * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
    461      * and <code>second</code>.
    462      *
    463      * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
    464      * @throws UnsupportedOperationException If implementation cannot support requested values.
    465      */
    466     public Duration newDurationDayTime(
    467             final boolean isPositive,
    468             final BigInteger day,
    469             final BigInteger hour,
    470             final BigInteger minute,
    471             final BigInteger second) {
    472 
    473         return newDuration(
    474                 isPositive,
    475                 null,  // years
    476                 null, // months
    477                 day,
    478                 hour,
    479                 minute,
    480                 (second != null)? new BigDecimal(second):null
    481         );
    482     }
    483 
    484     /**
    485      * <p>Create a <code>Duration</code> of type <code>xdt:dayTimeDuration</code> using the specified
    486      * <code>day</code>, <code>hour</code>, <code>minute</code> and <code>second</code> as defined in
    487      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-dayTimeDuration">
    488      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>.</p>
    489      *
    490      * <p>The datatype <code>xdt:dayTimeDuration</code> is a subtype of <code>xs:duration</code>
    491      * whose lexical representation contains only day, hour, minute, and second components.
    492      * This datatype resides in the namespace <code>http://www.w3.org/2003/11/xpath-datatypes</code>.</p>
    493      *
    494      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    495      *
    496      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    497      *   of the duration is zero, this parameter will be ignored.
    498      * @param day Day of <code>Duration</code>.
    499      * @param hour Hour of <code>Duration</code>.
    500      * @param minute Minute of <code>Duration</code>.
    501      * @param second Second of <code>Duration</code>.
    502      *
    503      * @return New <code>Duration</code> created with the specified <code>day</code>, <code>hour</code>, <code>minute</code>
    504      * and <code>second</code>.
    505      *
    506      * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
    507      */
    508     public Duration newDurationDayTime(
    509             final boolean isPositive,
    510             final int day,
    511             final int hour,
    512             final int minute,
    513             final int second) {
    514         return newDuration(isPositive,
    515                 DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
    516                 day, hour, minute, second);
    517     }
    518 
    519     /**
    520      * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
    521      * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthDuration">
    522      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
    523      *
    524      * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
    525      * whose lexical representation contains only year and month components.
    526      * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
    527      *
    528      * <p>Both values are set and available from the created {@link Duration}</p>
    529      *
    530      * <p>The XML Schema specification states that values can be of an arbitrary size.
    531      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    532      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    533      * if implementation capacities are exceeded.</p>
    534      *
    535      * @param lexicalRepresentation Lexical representation of a duration.
    536      *
    537      * @return New <code>Duration</code> created using the specified <code>lexicalRepresentation</code>.
    538      *
    539      * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> does not conform to the specification.
    540      * @throws UnsupportedOperationException If implementation cannot support requested values.
    541      * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
    542      */
    543     public Duration newDurationYearMonth(final String lexicalRepresentation) {
    544         if (lexicalRepresentation == null) {
    545             throw new NullPointerException("lexicalRepresentation == null");
    546         }
    547         // The lexical representation must match the pattern [^DT]*.
    548         int length = lexicalRepresentation.length();
    549         for (int i = 0; i < length; ++i) {
    550             char c = lexicalRepresentation.charAt(i);
    551             if (c == 'D' || c == 'T') {
    552                 throw new IllegalArgumentException("Invalid yearMonthDuration value: " + lexicalRepresentation);
    553             }
    554         }
    555         return newDuration(lexicalRepresentation);
    556     }
    557 
    558     /**
    559      * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
    560      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthDuration">
    561      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
    562      *
    563      * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
    564      * whose lexical representation contains only year and month components.
    565      * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
    566      *
    567      * <p>Both values are set by computing their values from the specified milliseconds
    568      * and are available using the <code>get</code> methods of  the created {@link Duration}.
    569      * The values conform to and are defined by:</p>
    570      * <ul>
    571      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
    572      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
    573      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
    574      *   </li>
    575      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
    576      * </ul>
    577      *
    578      * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
    579      * {@link java.util.Calendar#YEAR} = 1970,
    580      * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
    581      * {@link java.util.Calendar#DATE} = 1, etc.
    582      * This is important as there are variations in the Gregorian Calendar,
    583      * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
    584      * so the result of {@link Duration#getMonths()} can be influenced.</p>
    585      *
    586      * <p>Any remaining milliseconds after determining the year and month are discarded.</p>
    587      *
    588      * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
    589      *
    590      * @return New <code>Duration</code> created using the specified <code>durationInMilliseconds</code>.
    591      */
    592     public Duration newDurationYearMonth(final long durationInMilliseconds) {
    593 
    594         return newDuration(durationInMilliseconds);
    595     }
    596 
    597     /**
    598      * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
    599      * <code>year</code> and <code>month</code> as defined in
    600      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthyDuration">
    601      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
    602      *
    603      * <p>The XML Schema specification states that values can be of an arbitrary size.
    604      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
    605      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
    606      * if implementation capacities are exceeded.</p>
    607      *
    608      * <p>A <code>null</code> value indicates that field is not set.</p>
    609      *
    610      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    611      *   of the duration is zero, this parameter will be ignored.
    612      * @param year Year of <code>Duration</code>.
    613      * @param month Month of <code>Duration</code>.
    614      *
    615      * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
    616      *
    617      * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
    618      * @throws UnsupportedOperationException If implementation cannot support requested values.
    619      */
    620     public Duration newDurationYearMonth(
    621             final boolean isPositive,
    622             final BigInteger year,
    623             final BigInteger month) {
    624 
    625         return newDuration(
    626                 isPositive,
    627                 year,
    628                 month,
    629                 null, // days
    630                 null, // hours
    631                 null, // minutes
    632                 null  // seconds
    633         );
    634     }
    635 
    636     /**
    637      * <p>Create a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
    638      * <code>year</code> and <code>month</code> as defined in
    639      * <a href="http://www.w3.org/TR/xpath-datamodel#dt-yearMonthyDuration">
    640      *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
    641      *
    642      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    643      *
    644      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
    645      *   of the duration is zero, this parameter will be ignored.
    646      * @param year Year of <code>Duration</code>.
    647      * @param month Month of <code>Duration</code>.
    648      *
    649      * @return New <code>Duration</code> created using the specified <code>year</code> and <code>month</code>.
    650      *
    651      * @throws IllegalArgumentException If any values would create an invalid <code>Duration</code>.
    652      */
    653     public Duration newDurationYearMonth(
    654             final boolean isPositive,
    655             final int year,
    656             final int month) {
    657         return newDuration(isPositive, year, month,
    658                 DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED,
    659                 DatatypeConstants.FIELD_UNDEFINED, DatatypeConstants.FIELD_UNDEFINED);
    660     }
    661 
    662     /**
    663      * <p>Create a new instance of an <code>XMLGregorianCalendar</code>.</p>
    664      *
    665      * <p>All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null.</p>
    666      *
    667      * @return New <code>XMLGregorianCalendar</code> with all date/time datatype fields set to
    668      *   {@link DatatypeConstants#FIELD_UNDEFINED} or null.
    669      */
    670     public abstract XMLGregorianCalendar newXMLGregorianCalendar();
    671 
    672     /**
    673      * <p>Create a new XMLGregorianCalendar by parsing the String as a lexical representation.</p>
    674      *
    675      * <p>Parsing the lexical string representation is defined in
    676      * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1,
    677      * <em>Lexical Representation</em>.</a></p>
    678      *
    679      * <p>The string representation may not have any leading and trailing whitespaces.</p>
    680      *
    681      * <p>The parsing is done field by field so that
    682      * the following holds for any lexically correct String x:</p>
    683      * <pre>
    684      * newXMLGregorianCalendar(x).toXMLFormat().equals(x)
    685      * </pre>
    686      * <p>Except for the noted lexical/canonical representation mismatches
    687      * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45">
    688      * XML Schema 1.0 errata, Section 3.2.7.2</a>.</p>
    689      *
    690      * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes.
    691      *
    692      * @return <code>XMLGregorianCalendar</code> created from the <code>lexicalRepresentation</code>.
    693      *
    694      * @throws IllegalArgumentException If the <code>lexicalRepresentation</code> is not a valid <code>XMLGregorianCalendar</code>.
    695      * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
    696      */
    697     public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation);
    698 
    699     /**
    700      * <p>Create an <code>XMLGregorianCalendar</code> from a {@link GregorianCalendar}.</p>
    701      *
    702      * <table border="2" rules="all" cellpadding="2">
    703      *   <thead>
    704      *     <tr>
    705      *       <th align="center" colspan="2">
    706      *          Field by Field Conversion from
    707      *          {@link GregorianCalendar} to an {@link XMLGregorianCalendar}
    708      *       </th>
    709      *     </tr>
    710      *     <tr>
    711      *        <th><code>java.util.GregorianCalendar</code> field</th>
    712      *        <th><code>javax.xml.datatype.XMLGregorianCalendar</code> field</th>
    713      *     </tr>
    714      *   </thead>
    715      *   <tbody>
    716      *     <tr>
    717      *       <td><code>ERA == GregorianCalendar.BC ? -YEAR : YEAR</code></td>
    718      *       <td>{@link XMLGregorianCalendar#setYear(int year)}</td>
    719      *     </tr>
    720      *     <tr>
    721      *       <td><code>MONTH + 1</code></td>
    722      *       <td>{@link XMLGregorianCalendar#setMonth(int month)}</td>
    723      *     </tr>
    724      *     <tr>
    725      *       <td><code>DAY_OF_MONTH</code></td>
    726      *       <td>{@link XMLGregorianCalendar#setDay(int day)}</td>
    727      *     </tr>
    728      *     <tr>
    729      *       <td><code>HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND</code></td>
    730      *       <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td>
    731      *     </tr>
    732      *     <tr>
    733      *       <td>
    734      *         <code>(ZONE_OFFSET + DST_OFFSET) / (60*1000)</code><br/>
    735      *         <em>(in minutes)</em>
    736      *       </td>
    737      *       <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup>
    738      *       </td>
    739      *     </tr>
    740      *   </tbody>
    741      * </table>
    742      * <p><em>*</em>conversion loss of information. It is not possible to represent
    743      * a <code>java.util.GregorianCalendar</code> daylight savings timezone id in the
    744      * XML Schema 1.0 date/time datatype representation.</p>
    745      *
    746      * <p>To compute the return value's <code>TimeZone</code> field,
    747      * <ul>
    748      * <li>when <code>this.getTimezone() != FIELD_UNDEFINED</code>,
    749      * create a <code>java.util.TimeZone</code> with a custom timezone id
    750      * using the <code>this.getTimezone()</code>.</li>
    751      * <li>else use the <code>GregorianCalendar</code> default timezone value
    752      * for the host is defined as specified by
    753      * <code>java.util.TimeZone.getDefault()</code>.</li></p>
    754      *
    755      * @param cal <code>java.util.GregorianCalendar</code> used to create <code>XMLGregorianCalendar</code>
    756      *
    757      * @return <code>XMLGregorianCalendar</code> created from <code>java.util.GregorianCalendar</code>
    758      *
    759      * @throws NullPointerException If <code>cal</code> is <code>null</code>.
    760      */
    761     public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal);
    762 
    763     /**
    764      * <p>Constructor allowing for complete value spaces allowed by
    765      * W3C XML Schema 1.0 recommendation for xsd:dateTime and related
    766      * builtin datatypes. Note that <code>year</code> parameter supports
    767      * arbitrarily large numbers and fractionalSecond has infinite
    768      * precision.</p>
    769      *
    770      * <p>A <code>null</code> value indicates that field is not set.</p>
    771      *
    772      * @param year of <code>XMLGregorianCalendar</code> to be created.
    773      * @param month of <code>XMLGregorianCalendar</code> to be created.
    774      * @param day of <code>XMLGregorianCalendar</code> to be created.
    775      * @param hour of <code>XMLGregorianCalendar</code> to be created.
    776      * @param minute of <code>XMLGregorianCalendar</code> to be created.
    777      * @param second of <code>XMLGregorianCalendar</code> to be created.
    778      * @param fractionalSecond of <code>XMLGregorianCalendar</code> to be created.
    779      * @param timezone of <code>XMLGregorianCalendar</code> to be created.
    780      *
    781      * @return <code>XMLGregorianCalendar</code> created from specified values.
    782      *
    783      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    784      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    785      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    786      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    787      */
    788     public abstract XMLGregorianCalendar newXMLGregorianCalendar(
    789             final BigInteger year,
    790             final int month,
    791             final int day,
    792             final int hour,
    793             final int minute,
    794             final int second,
    795             final BigDecimal fractionalSecond,
    796             final int timezone);
    797 
    798     /**
    799      * <p>Constructor of value spaces that a
    800      * <code>java.util.GregorianCalendar</code> instance would need to convert to an
    801      * <code>XMLGregorianCalendar</code> instance.</p>
    802      *
    803      * <p><code>XMLGregorianCalendar eon</code> and
    804      * <code>fractionalSecond</code> are set to <code>null</code></p>
    805      *
    806      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    807      *
    808      * @param year of <code>XMLGregorianCalendar</code> to be created.
    809      * @param month of <code>XMLGregorianCalendar</code> to be created.
    810      * @param day of <code>XMLGregorianCalendar</code> to be created.
    811      * @param hour of <code>XMLGregorianCalendar</code> to be created.
    812      * @param minute of <code>XMLGregorianCalendar</code> to be created.
    813      * @param second of <code>XMLGregorianCalendar</code> to be created.
    814      * @param millisecond of <code>XMLGregorianCalendar</code> to be created.
    815      * @param timezone of <code>XMLGregorianCalendar</code> to be created.
    816      *
    817      * @return <code>XMLGregorianCalendar</code> created from specified values.
    818      *
    819      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    820      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    821      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    822      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    823      */
    824     public XMLGregorianCalendar newXMLGregorianCalendar(
    825             final int year,
    826             final int month,
    827             final int day,
    828             final int hour,
    829             final int minute,
    830             final int second,
    831             final int millisecond,
    832             final int timezone) {
    833 
    834         // year may be undefined
    835         BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null;
    836 
    837         // millisecond may be undefined
    838         // millisecond must be >= 0 millisecond <= 1000
    839         BigDecimal realMillisecond = null; // undefined value
    840         if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
    841             if (millisecond < 0 || millisecond > 1000) {
    842                 throw new IllegalArgumentException(
    843                         "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar("
    844                         + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)"
    845                         + "with invalid millisecond: " + millisecond
    846                 );
    847             }
    848             realMillisecond = BigDecimal.valueOf((long) millisecond, 3);
    849         }
    850 
    851         return newXMLGregorianCalendar(
    852                 realYear,
    853                 month,
    854                 day,
    855                 hour,
    856                 minute,
    857                 second,
    858                 realMillisecond,
    859                 timezone
    860         );
    861     }
    862 
    863     /**
    864      * <p>Create a Java representation of XML Schema builtin datatype <code>date</code> or <code>g*</code>.</p>
    865      *
    866      * <p>For example, an instance of <code>gYear</code> can be created invoking this factory
    867      * with <code>month</code> and <code>day</code> parameters set to
    868      * {@link DatatypeConstants#FIELD_UNDEFINED}.</p>
    869      *
    870      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    871      *
    872      * @param year of <code>XMLGregorianCalendar</code> to be created.
    873      * @param month of <code>XMLGregorianCalendar</code> to be created.
    874      * @param day of <code>XMLGregorianCalendar</code> to be created.
    875      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
    876      *
    877      * @return <code>XMLGregorianCalendar</code> created from parameter values.
    878      *
    879      * @see DatatypeConstants#FIELD_UNDEFINED
    880      *
    881      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    882      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    883      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    884      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    885      */
    886     public XMLGregorianCalendar newXMLGregorianCalendarDate(
    887             final int year,
    888             final int month,
    889             final int day,
    890             final int timezone) {
    891 
    892         return newXMLGregorianCalendar(
    893                 year,
    894                 month,
    895                 day,
    896                 DatatypeConstants.FIELD_UNDEFINED, // hour
    897                 DatatypeConstants.FIELD_UNDEFINED, // minute
    898                 DatatypeConstants.FIELD_UNDEFINED, // second
    899                 DatatypeConstants.FIELD_UNDEFINED, // millisecond
    900                 timezone);
    901     }
    902 
    903     /**
    904      * <p>Create a Java instance of XML Schema builtin datatype <code>time</code>.</p>
    905      *
    906      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    907      *
    908      * @param hours number of hours
    909      * @param minutes number of minutes
    910      * @param seconds number of seconds
    911      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
    912      *
    913      * @return <code>XMLGregorianCalendar</code> created from parameter values.
    914      *
    915      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    916      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    917      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    918      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    919      *
    920      * @see DatatypeConstants#FIELD_UNDEFINED
    921      */
    922     public XMLGregorianCalendar newXMLGregorianCalendarTime(
    923             final int hours,
    924             final int minutes,
    925             final int seconds,
    926             final int timezone) {
    927 
    928         return newXMLGregorianCalendar(
    929                 DatatypeConstants.FIELD_UNDEFINED, // Year
    930                 DatatypeConstants.FIELD_UNDEFINED, // Month
    931                 DatatypeConstants.FIELD_UNDEFINED, // Day
    932                 hours,
    933                 minutes,
    934                 seconds,
    935                 DatatypeConstants.FIELD_UNDEFINED, //Millisecond
    936                 timezone);
    937     }
    938 
    939     /**
    940      * <p>Create a Java instance of XML Schema builtin datatype time.</p>
    941      *
    942      * <p>A <code>null</code> value indicates that field is not set.</p>
    943      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    944      *
    945      * @param hours number of hours
    946      * @param minutes number of minutes
    947      * @param seconds number of seconds
    948      * @param fractionalSecond value of <code>null</code> indicates that this optional field is not set.
    949      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
    950      *
    951      * @return <code>XMLGregorianCalendar</code> created from parameter values.
    952      *
    953      * @see DatatypeConstants#FIELD_UNDEFINED
    954      *
    955      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    956      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    957      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    958      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    959      */
    960     public XMLGregorianCalendar newXMLGregorianCalendarTime(
    961             final int hours,
    962             final int minutes,
    963             final int seconds,
    964             final BigDecimal fractionalSecond,
    965             final int timezone) {
    966 
    967         return newXMLGregorianCalendar(
    968                 null, // year
    969                 DatatypeConstants.FIELD_UNDEFINED, // month
    970                 DatatypeConstants.FIELD_UNDEFINED, // day
    971                 hours,
    972                 minutes,
    973                 seconds,
    974                 fractionalSecond,
    975                 timezone);
    976     }
    977 
    978     /**
    979      * <p>Create a Java instance of XML Schema builtin datatype time.</p>
    980      *
    981      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
    982      *
    983      * @param hours number of hours
    984      * @param minutes number of minutes
    985      * @param seconds number of seconds
    986      * @param milliseconds number of milliseconds
    987      * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set.
    988      *
    989      * @return <code>XMLGregorianCalendar</code> created from parameter values.
    990      *
    991      * @see DatatypeConstants#FIELD_UNDEFINED
    992      *
    993      * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field
    994      *   as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar}
    995      *   or if the composite values constitute an invalid <code>XMLGregorianCalendar</code> instance
    996      *   as determined by {@link XMLGregorianCalendar#isValid()}.
    997      */
    998     public XMLGregorianCalendar newXMLGregorianCalendarTime(
    999             final int hours,
   1000             final int minutes,
   1001             final int seconds,
   1002             final int milliseconds,
   1003             final int timezone) {
   1004 
   1005         // millisecond may be undefined
   1006         // millisecond must be >= 0 millisecond <= 1000
   1007         BigDecimal realMilliseconds = null; // undefined value
   1008         if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) {
   1009             if (milliseconds < 0 || milliseconds > 1000) {
   1010                 throw new IllegalArgumentException(
   1011                         "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime("
   1012                         + "int hours, int minutes, int seconds, int milliseconds, int timezone)"
   1013                         + "with invalid milliseconds: " + milliseconds
   1014                 );
   1015             }
   1016             realMilliseconds = BigDecimal.valueOf((long) milliseconds, 3);
   1017         }
   1018 
   1019         return newXMLGregorianCalendarTime(
   1020                 hours,
   1021                 minutes,
   1022                 seconds,
   1023                 realMilliseconds,
   1024                 timezone
   1025         );
   1026     }
   1027 }
   1028