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