1 /* 2 * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.datatype; 27 28 import java.math.BigDecimal; 29 import java.math.BigInteger; 30 import java.util.GregorianCalendar; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 import com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl; 34 35 /** 36 * Factory that creates new {@code javax.xml.datatype} {@code Object}s that map XML to/from Java {@code Object}s. 37 * <p> 38 * A new instance of the {@code DatatypeFactory} is created through the {@link #newInstance()} method 39 * that uses the following implementation resolution mechanisms to determine an implementation: 40 * <ol> 41 * <li> 42 * If the system property specified by {@link #DATATYPEFACTORY_PROPERTY}, "{@code javax.xml.datatype.DatatypeFactory}", 43 * exists, a class with the name of the property value is instantiated. 44 * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. 45 * </li> 46 * <li> 47 * <p> 48 * Use the configuration file "jaxp.properties". The file is in standard 49 * {@link java.util.Properties} format and typically located in the 50 * {@code conf} directory of the Java installation. It contains the fully qualified 51 * name of the implementation class with the key being the system property 52 * defined above. 53 * <p> 54 * The jaxp.properties file is read only once by the JAXP implementation 55 * and its values are then cached for future use. If the file does not exist 56 * when the first attempt is made to read from it, no further attempts are 57 * made to check for its existence. It is not possible to change the value 58 * of any property in jaxp.properties after it has been read for the first time. 59 * </li> 60 * <li> 61 * <p> 62 * Use the service-provider loading facility, defined by the {@link java.util.ServiceLoader} class, to attempt 63 * to locate and load an implementation of the service using the {@linkplain 64 * java.util.ServiceLoader#load(java.lang.Class) default loading mechanism}: 65 * the service-provider loading facility will use the {@linkplain 66 * java.lang.Thread#getContextClassLoader() current thread's context class loader} 67 * to attempt to load the service. If the context class 68 * loader is null, the {@linkplain 69 * ClassLoader#getSystemClassLoader() system class loader} will be used. 70 * <p> 71 * In case of {@link java.util.ServiceConfigurationError service 72 * configuration error}, a {@link javax.xml.datatype.DatatypeConfigurationException} 73 * will be thrown. 74 * </li> 75 * <li> 76 * <p> 77 * The final mechanism is to attempt to instantiate the {@code Class} specified by 78 * {@link #DATATYPEFACTORY_IMPLEMENTATION_CLASS}. 79 * Any Exception thrown during the instantiation process is wrapped as a {@link DatatypeConfigurationException}. 80 * </li> 81 * </ol> 82 * 83 * @author <a href="mailto:Joseph.Fialli@Sun.COM">Joseph Fialli</a> 84 * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a> 85 * @author <a href="mailto:Neeraj.Bajaj@sun.com">Neeraj Bajaj</a> 86 * 87 * @since 1.5 88 */ 89 public abstract class DatatypeFactory { 90 91 /** 92 * Default property name as defined in JSR 206: Java(TM) API for XML Processing (JAXP) 1.3. 93 * 94 * <p>Default value is {@code javax.xml.datatype.DatatypeFactory}. 95 */ 96 public static final String DATATYPEFACTORY_PROPERTY = 97 // We use a String constant here, rather than calling 98 // DatatypeFactory.class.getName() - in order to make javadoc 99 // generate a See Also: Constant Field Value link. 100 "javax.xml.datatype.DatatypeFactory"; 101 102 /** 103 * Default implementation class name as defined in 104 * <em>JSR 206: Java(TM) API for XML Processing (JAXP) 1.3</em>. 105 * 106 * <p>Implementers should specify the name of an appropriate class 107 * to be instantiated if no other implementation resolution mechanism 108 * succeeds. 109 * 110 * <p>Users should not refer to this field; it is intended only to 111 * document a factory implementation detail. 112 */ 113 public static final String DATATYPEFACTORY_IMPLEMENTATION_CLASS = 114 // We use new String() here to prevent javadoc from generating 115 // a See Also: Constant Field Value link. 116 new String("com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl"); 117 118 /** 119 * http://www.w3.org/TR/xpath-datamodel/#xdtschema defines two regexps 120 * to constrain the value space of dayTimeDuration ([^YM]*[DT].*) 121 * and yearMonthDuration ([^DT]*). Note that these expressions rely on 122 * the fact that the value must be an xs:Duration, they simply exclude 123 * some Durations. 124 */ 125 private static final Pattern XDTSCHEMA_YMD = 126 Pattern.compile("[^DT]*"); 127 128 private static final Pattern XDTSCHEMA_DTD = 129 Pattern.compile("[^YM]*[DT].*"); 130 131 /** 132 * Protected constructor to prevent instantiation outside of package. 133 * 134 * <p>Use {@link #newInstance()} to create a {@code DatatypeFactory}. 135 */ 136 protected DatatypeFactory() { 137 } 138 139 /** 140 * Creates a new instance of the {@code DatatypeFactory} {@linkplain 141 * #DATATYPEFACTORY_IMPLEMENTATION_CLASS builtin system-default 142 * implementation}. 143 * 144 * @return A new instance of the {@code DatatypeFactory} builtin 145 * system-default implementation. 146 * 147 * @since 9 148 */ 149 public static DatatypeFactory newDefaultInstance() { 150 return new DatatypeFactoryImpl(); 151 } 152 153 /** 154 * Obtain a new instance of a {@code DatatypeFactory}. 155 * 156 * <p>The implementation resolution mechanisms are <a href="#DatatypeFactory.newInstance">defined</a> in this 157 * {@code Class}'s documentation. 158 * 159 * @return New instance of a {@code DatatypeFactory} 160 * 161 * @throws DatatypeConfigurationException If the implementation is not 162 * available or cannot be instantiated. 163 * 164 * @see #newInstance(String factoryClassName, ClassLoader classLoader) 165 */ 166 public static DatatypeFactory newInstance() 167 throws DatatypeConfigurationException { 168 169 return FactoryFinder.find( 170 /* The default property name according to the JAXP spec */ 171 DatatypeFactory.class, 172 /* The fallback implementation class name */ 173 DATATYPEFACTORY_IMPLEMENTATION_CLASS); 174 } 175 176 /** 177 * Obtain a new instance of a {@code DatatypeFactory} from class name. 178 * This function is useful when there are multiple providers in the classpath. 179 * It gives more control to the application as it can specify which provider 180 * should be loaded. 181 * 182 * <p>Once an application has obtained a reference to a {@code DatatypeFactory} 183 * it can use the factory to configure and obtain datatype instances. 184 * 185 * 186 * <h2>Tip for Trouble-shooting</h2> 187 * <p>Setting the {@code jaxp.debug} system property will cause 188 * this method to print a lot of debug messages 189 * to {@code System.err} about what it is doing and where it is looking at. 190 * 191 * <p> If you have problems try: 192 * <pre> 193 * java -Djaxp.debug=1 YourProgram .... 194 * </pre> 195 * 196 * @param factoryClassName fully qualified factory class name that provides implementation of {@code javax.xml.datatype.DatatypeFactory}. 197 * 198 * @param classLoader {@code ClassLoader} used to load the factory class. If {@code null} 199 * current {@code Thread}'s context classLoader is used to load the factory class. 200 * 201 * @return New instance of a {@code DatatypeFactory} 202 * 203 * @throws DatatypeConfigurationException if {@code factoryClassName} is {@code null}, or 204 * the factory class cannot be loaded, instantiated. 205 * 206 * @see #newInstance() 207 * 208 * @since 1.6 209 */ 210 public static DatatypeFactory newInstance(String factoryClassName, ClassLoader classLoader) 211 throws DatatypeConfigurationException { 212 return FactoryFinder.newInstance(DatatypeFactory.class, 213 factoryClassName, classLoader, false); 214 } 215 216 /** 217 * Obtain a new instance of a {@code Duration} 218 * specifying the {@code Duration} as its string representation, "PnYnMnDTnHnMnS", 219 * as defined in XML Schema 1.0 section 3.2.6.1. 220 * 221 * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines {@code duration} as: 222 * <blockquote> 223 * duration represents a duration of time. 224 * The value space of duration is a six-dimensional space where the coordinates designate the 225 * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. 226 * These components are ordered in their significance by their order of appearance i.e. as 227 * year, month, day, hour, minute, and second. 228 * </blockquote> 229 * <p>All six values are set and available from the created {@link Duration} 230 * 231 * <p>The XML Schema specification states that values can be of an arbitrary size. 232 * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. 233 * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits 234 * if implementation capacities are exceeded. 235 * 236 * @param lexicalRepresentation {@code String} representation of a {@code Duration}. 237 * 238 * @return New {@code Duration} created from parsing the {@code lexicalRepresentation}. 239 * 240 * @throws IllegalArgumentException If {@code lexicalRepresentation} is not a valid representation of a {@code Duration}. 241 * @throws UnsupportedOperationException If implementation cannot support requested values. 242 * @throws NullPointerException if {@code lexicalRepresentation} is {@code null}. 243 */ 244 public abstract Duration newDuration(final String lexicalRepresentation); 245 246 /** 247 * Obtain a new instance of a {@code Duration} 248 * specifying the {@code Duration} as milliseconds. 249 * 250 * <p>XML Schema Part 2: Datatypes, 3.2.6 duration, defines {@code duration} as: 251 * <blockquote> 252 * duration represents a duration of time. 253 * The value space of duration is a six-dimensional space where the coordinates designate the 254 * Gregorian year, month, day, hour, minute, and second components defined in Section 5.5.3.2 of [ISO 8601], respectively. 255 * These components are ordered in their significance by their order of appearance i.e. as 256 * year, month, day, hour, minute, and second. 257 * </blockquote> 258 * <p>All six values are set by computing their values from the specified milliseconds 259 * and are available using the {@code get} methods of the created {@link Duration}. 260 * The values conform to and are defined by: 261 * <ul> 262 * <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li> 263 * <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats"> 264 * W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a> 265 * </li> 266 * <li>{@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li> 267 * </ul> 268 * 269 * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., 270 * {@link java.util.Calendar#YEAR} = 1970, 271 * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, 272 * {@link java.util.Calendar#DATE} = 1, etc. 273 * This is important as there are variations in the Gregorian Calendar, 274 * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} 275 * so the result of {@link Duration#getMonths()} and {@link Duration#getDays()} can be influenced. 276 * 277 * @param durationInMilliSeconds Duration in milliseconds to create. 278 * 279 * @return New {@code Duration} representing {@code durationInMilliSeconds}. 280 */ 281 public abstract Duration newDuration(final long durationInMilliSeconds); 282 283 /** 284 * Obtain a new instance of a {@code Duration} 285 * specifying the {@code Duration} as isPositive, years, months, days, hours, minutes, seconds. 286 * 287 * <p>The XML Schema specification states that values can be of an arbitrary size. 288 * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. 289 * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits 290 * if implementation capacities are exceeded. 291 * 292 * <p>A {@code null} value indicates that field is not set. 293 * 294 * @param isPositive Set to {@code false} to create a negative duration. When the length 295 * of the duration is zero, this parameter will be ignored. 296 * @param years of this {@code Duration} 297 * @param months of this {@code Duration} 298 * @param days of this {@code Duration} 299 * @param hours of this {@code Duration} 300 * @param minutes of this {@code Duration} 301 * @param seconds of this {@code Duration} 302 * 303 * @return New {@code Duration} created from the specified values. 304 * 305 * @throws IllegalArgumentException If the values are not a valid representation of a 306 * {@code Duration}: if all the fields (years, months, ...) are null or 307 * if any of the fields is negative. 308 * @throws UnsupportedOperationException If implementation cannot support requested values. 309 */ 310 public abstract Duration newDuration( 311 final boolean isPositive, 312 final BigInteger years, 313 final BigInteger months, 314 final BigInteger days, 315 final BigInteger hours, 316 final BigInteger minutes, 317 final BigDecimal seconds); 318 319 /** 320 * Obtain a new instance of a {@code Duration} 321 * specifying the {@code Duration} as isPositive, years, months, days, hours, minutes, seconds. 322 * 323 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 324 * 325 * @param isPositive Set to {@code false} to create a negative duration. When the length 326 * of the duration is zero, this parameter will be ignored. 327 * @param years of this {@code Duration} 328 * @param months of this {@code Duration} 329 * @param days of this {@code Duration} 330 * @param hours of this {@code Duration} 331 * @param minutes of this {@code Duration} 332 * @param seconds of this {@code Duration} 333 * 334 * @return New {@code Duration} created from the specified values. 335 * 336 * @throws IllegalArgumentException If the values are not a valid representation of a 337 * {@code Duration}: if any of the fields is negative. 338 * 339 * @see #newDuration( 340 * boolean isPositive, 341 * BigInteger years, 342 * BigInteger months, 343 * BigInteger days, 344 * BigInteger hours, 345 * BigInteger minutes, 346 * BigDecimal seconds) 347 */ 348 public Duration newDuration( 349 final boolean isPositive, 350 final int years, 351 final int months, 352 final int days, 353 final int hours, 354 final int minutes, 355 final int seconds) { 356 357 // years may not be set 358 BigInteger realYears = (years != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) years) : null; 359 360 // months may not be set 361 BigInteger realMonths = (months != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) months) : null; 362 363 // days may not be set 364 BigInteger realDays = (days != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) days) : null; 365 366 // hours may not be set 367 BigInteger realHours = (hours != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) hours) : null; 368 369 // minutes may not be set 370 BigInteger realMinutes = (minutes != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) minutes) : null; 371 372 // seconds may not be set 373 BigDecimal realSeconds = (seconds != DatatypeConstants.FIELD_UNDEFINED) ? BigDecimal.valueOf((long) seconds) : null; 374 375 return newDuration( 376 isPositive, 377 realYears, 378 realMonths, 379 realDays, 380 realHours, 381 realMinutes, 382 realSeconds 383 ); 384 } 385 386 /** 387 * Create a {@code Duration} of type {@code xdt:dayTimeDuration} 388 * by parsing its {@code String} representation, 389 * "<em>PnDTnHnMnS</em>", <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration"> 390 * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>. 391 * 392 * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration} 393 * whose lexical representation contains only day, hour, minute, and second components. 394 * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}. 395 * 396 * <p>All four values are set and available from the created {@link Duration} 397 * 398 * <p>The XML Schema specification states that values can be of an arbitrary size. 399 * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. 400 * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits 401 * if implementation capacities are exceeded. 402 * 403 * @param lexicalRepresentation Lexical representation of a duration. 404 * 405 * @return New {@code Duration} created using the specified {@code lexicalRepresentation}. 406 * 407 * @throws IllegalArgumentException If {@code lexicalRepresentation} is 408 * not a valid representation of a {@code Duration} expressed only in terms of days and time. 409 * @throws UnsupportedOperationException If implementation cannot support requested values. 410 * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}. 411 */ 412 public Duration newDurationDayTime(final String lexicalRepresentation) { 413 // lexicalRepresentation must be non-null 414 if (lexicalRepresentation == null) { 415 throw new NullPointerException( 416 "Trying to create an xdt:dayTimeDuration with an invalid" 417 + " lexical representation of \"null\""); 418 } 419 420 // test lexicalRepresentation against spec regex 421 Matcher matcher = XDTSCHEMA_DTD.matcher(lexicalRepresentation); 422 if (!matcher.matches()) { 423 throw new IllegalArgumentException( 424 "Trying to create an xdt:dayTimeDuration with an invalid" 425 + " lexical representation of \"" + lexicalRepresentation 426 + "\", data model requires years and months only."); 427 } 428 429 return newDuration(lexicalRepresentation); 430 } 431 432 /** 433 * Create a {@code Duration} of type {@code xdt:dayTimeDuration} 434 * using the specified milliseconds as defined in 435 * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration"> 436 * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>. 437 * 438 * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration} 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}. 441 * 442 * <p>All four values are set by computing their values from the specified milliseconds 443 * and are available using the {@code get} methods of the created {@link Duration}. 444 * The values conform to and are defined by: 445 * <ul> 446 * <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li> 447 * <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats"> 448 * W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a> 449 * </li> 450 * <li>{@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li> 451 * </ul> 452 * 453 * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., 454 * {@link java.util.Calendar#YEAR} = 1970, 455 * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, 456 * {@link java.util.Calendar#DATE} = 1, etc. 457 * This is important as there are variations in the Gregorian Calendar, 458 * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} 459 * so the result of {@link Duration#getDays()} can be influenced. 460 * 461 * <p>Any remaining milliseconds after determining the day, hour, minute and second are discarded. 462 * 463 * @param durationInMilliseconds Milliseconds of {@code Duration} to create. 464 * 465 * @return New {@code Duration} created with the specified {@code durationInMilliseconds}. 466 * 467 * @see <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration"> 468 * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a> 469 */ 470 public Duration newDurationDayTime(final long durationInMilliseconds) { 471 472 return newDuration(durationInMilliseconds); 473 } 474 475 /** 476 * Create a {@code Duration} of type {@code xdt:dayTimeDuration} using the specified 477 * {@code day}, {@code hour}, {@code minute} and {@code second} as defined in 478 * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration"> 479 * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>. 480 * 481 * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration} 482 * whose lexical representation contains only day, hour, minute, and second components. 483 * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}. 484 * 485 * <p>The XML Schema specification states that values can be of an arbitrary size. 486 * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. 487 * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits 488 * if implementation capacities are exceeded. 489 * 490 * <p>A {@code null} value indicates that field is not set. 491 * 492 * @param isPositive Set to {@code false} 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}. 495 * @param hour Hour of {@code Duration}. 496 * @param minute Minute of {@code Duration}. 497 * @param second Second of {@code Duration}. 498 * 499 * @return New {@code Duration} created with the specified {@code day}, {@code hour}, {@code minute} 500 * and {@code second}. 501 * 502 * @throws IllegalArgumentException If the values are not a valid representation of a 503 * {@code Duration}: if all the fields (day, hour, ...) are null or 504 * if any of the fields is negative. 505 * @throws UnsupportedOperationException If implementation cannot support requested values. 506 */ 507 public Duration newDurationDayTime( 508 final boolean isPositive, 509 final BigInteger day, 510 final BigInteger hour, 511 final BigInteger minute, 512 final BigInteger second) { 513 514 return newDuration( 515 isPositive, 516 null, // years 517 null, // months 518 day, 519 hour, 520 minute, 521 (second != null)? new BigDecimal(second):null 522 ); 523 } 524 525 /** 526 * Create a {@code Duration} of type {@code xdt:dayTimeDuration} using the specified 527 * {@code day}, {@code hour}, {@code minute} and {@code second} as defined in 528 * <a href="http://www.w3.org/TR/xpath-datamodel#dayTimeDuration"> 529 * XQuery 1.0 and XPath 2.0 Data Model, xdt:dayTimeDuration</a>. 530 * 531 * <p>The datatype {@code xdt:dayTimeDuration} is a subtype of {@code xs:duration} 532 * whose lexical representation contains only day, hour, minute, and second components. 533 * This datatype resides in the namespace {@code http://www.w3.org/2003/11/xpath-datatypes}. 534 * 535 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 536 * 537 * @param isPositive Set to {@code false} to create a negative duration. When the length 538 * of the duration is zero, this parameter will be ignored. 539 * @param day Day of {@code Duration}. 540 * @param hour Hour of {@code Duration}. 541 * @param minute Minute of {@code Duration}. 542 * @param second Second of {@code Duration}. 543 * 544 * @return New {@code Duration} created with the specified {@code day}, {@code hour}, {@code minute} 545 * and {@code second}. 546 * 547 * @throws IllegalArgumentException If the values are not a valid representation of a 548 * {@code Duration}: if any of the fields (day, hour, ...) is negative. 549 */ 550 public Duration newDurationDayTime( 551 final boolean isPositive, 552 final int day, 553 final int hour, 554 final int minute, 555 final int second) { 556 557 return newDurationDayTime( 558 isPositive, 559 BigInteger.valueOf((long) day), 560 BigInteger.valueOf((long) hour), 561 BigInteger.valueOf((long) minute), 562 BigInteger.valueOf((long) second) 563 ); 564 } 565 566 /** 567 * Create a {@code Duration} of type {@code xdt:yearMonthDuration} 568 * by parsing its {@code String} representation, 569 * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration"> 570 * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>. 571 * 572 * <p>The datatype {@code xdt:yearMonthDuration} is a subtype of {@code xs:duration} 573 * whose lexical representation contains only year and month components. 574 * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}. 575 * 576 * <p>Both values are set and available from the created {@link Duration} 577 * 578 * <p>The XML Schema specification states that values can be of an arbitrary size. 579 * Implementations may chose not to or be incapable of supporting 580 * arbitrarily large and/or small values. An {@link UnsupportedOperationException} 581 * will be thrown with a message indicating implementation limits 582 * if implementation capacities are exceeded. 583 * 584 * @param lexicalRepresentation Lexical representation of a duration. 585 * 586 * @return New {@code Duration} created using the specified {@code lexicalRepresentation}. 587 * 588 * @throws IllegalArgumentException If {@code lexicalRepresentation} is not a valid representation of a {@code Duration} expressed only in terms of years and months. 589 * @throws UnsupportedOperationException If implementation cannot support requested values. 590 * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}. 591 */ 592 public Duration newDurationYearMonth( 593 final String lexicalRepresentation) { 594 595 // lexicalRepresentation must be non-null 596 if (lexicalRepresentation == null) { 597 throw new NullPointerException( 598 "Trying to create an xdt:yearMonthDuration with an invalid" 599 + " lexical representation of \"null\""); 600 } 601 602 // test lexicalRepresentation against spec regex 603 Matcher matcher = XDTSCHEMA_YMD.matcher(lexicalRepresentation); 604 if (!matcher.matches()) { 605 throw new IllegalArgumentException( 606 "Trying to create an xdt:yearMonthDuration with an invalid" 607 + " lexical representation of \"" + lexicalRepresentation 608 + "\", data model requires days and times only."); 609 } 610 611 return newDuration(lexicalRepresentation); 612 } 613 614 /** 615 * Create a {@code Duration} of type {@code xdt:yearMonthDuration} 616 * using the specified milliseconds as defined in 617 * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration"> 618 * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>. 619 * 620 * <p>The datatype {@code xdt:yearMonthDuration} is a subtype of {@code xs:duration} 621 * whose lexical representation contains only year and month components. 622 * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}. 623 * 624 * <p>Both values are set by computing their values from the specified milliseconds 625 * and are available using the {@code get} methods of the created {@link Duration}. 626 * The values conform to and are defined by: 627 * <ul> 628 * <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li> 629 * <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats"> 630 * W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a> 631 * </li> 632 * <li>{@link XMLGregorianCalendar} Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li> 633 * </ul> 634 * 635 * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e., 636 * {@link java.util.Calendar#YEAR} = 1970, 637 * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY}, 638 * {@link java.util.Calendar#DATE} = 1, etc. 639 * This is important as there are variations in the Gregorian Calendar, 640 * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY} 641 * so the result of {@link Duration#getMonths()} can be influenced. 642 * 643 * <p>Any remaining milliseconds after determining the year and month are discarded. 644 * 645 * @param durationInMilliseconds Milliseconds of {@code Duration} to create. 646 * 647 * @return New {@code Duration} created using the specified {@code durationInMilliseconds}. 648 */ 649 public Duration newDurationYearMonth( 650 final long durationInMilliseconds) { 651 652 // create a Duration that only has sign, year & month 653 // Duration is immutable, so need to create a new Duration 654 // implementations may override this method in a more efficient way 655 Duration fullDuration = newDuration(durationInMilliseconds); 656 boolean isPositive = (fullDuration.getSign() == -1) ? false : true; 657 BigInteger years = 658 (BigInteger) fullDuration.getField(DatatypeConstants.YEARS); 659 if (years == null) { years = BigInteger.ZERO; } 660 BigInteger months = 661 (BigInteger) fullDuration.getField(DatatypeConstants.MONTHS); 662 if (months == null) { months = BigInteger.ZERO; } 663 664 return newDurationYearMonth(isPositive, years, months); 665 } 666 667 /** 668 * Create a {@code Duration} of type {@code xdt:yearMonthDuration} using the specified 669 * {@code year} and {@code month} as defined in 670 * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration"> 671 * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>. 672 * 673 * <p>The XML Schema specification states that values can be of an arbitrary size. 674 * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values. 675 * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits 676 * if implementation capacities are exceeded. 677 * 678 * <p>A {@code null} value indicates that field is not set. 679 * 680 * @param isPositive Set to {@code false} to create a negative duration. When the length 681 * of the duration is zero, this parameter will be ignored. 682 * @param year Year of {@code Duration}. 683 * @param month Month of {@code Duration}. 684 * 685 * @return New {@code Duration} created using the specified {@code year} and {@code month}. 686 * 687 * @throws IllegalArgumentException If the values are not a valid representation of a 688 * {@code Duration}: if all of the fields (year, month) are null or 689 * if any of the fields is negative. 690 * @throws UnsupportedOperationException If implementation cannot support requested values. 691 */ 692 public Duration newDurationYearMonth( 693 final boolean isPositive, 694 final BigInteger year, 695 final BigInteger month) { 696 697 return newDuration( 698 isPositive, 699 year, 700 month, 701 null, // days 702 null, // hours 703 null, // minutes 704 null // seconds 705 ); 706 } 707 708 /** 709 * Create a {@code Duration} of type {@code xdt:yearMonthDuration} using the specified 710 * {@code year} and {@code month} as defined in 711 * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration"> 712 * XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>. 713 * 714 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 715 * 716 * @param isPositive Set to {@code false} to create a negative duration. When the length 717 * of the duration is zero, this parameter will be ignored. 718 * @param year Year of {@code Duration}. 719 * @param month Month of {@code Duration}. 720 * 721 * @return New {@code Duration} created using the specified {@code year} and {@code month}. 722 * 723 * @throws IllegalArgumentException If the values are not a valid representation of a 724 * {@code Duration}: if any of the fields (year, month) is negative. 725 */ 726 public Duration newDurationYearMonth( 727 final boolean isPositive, 728 final int year, 729 final int month) { 730 731 return newDurationYearMonth( 732 isPositive, 733 BigInteger.valueOf((long) year), 734 BigInteger.valueOf((long) month)); 735 } 736 737 /** 738 * Create a new instance of an {@code XMLGregorianCalendar}. 739 * 740 * <p>All date/time datatype fields set to {@link DatatypeConstants#FIELD_UNDEFINED} or null. 741 * 742 * @return New {@code XMLGregorianCalendar} with all date/time datatype fields set to 743 * {@link DatatypeConstants#FIELD_UNDEFINED} or null. 744 */ 745 public abstract XMLGregorianCalendar newXMLGregorianCalendar(); 746 747 /** 748 * Create a new XMLGregorianCalendar by parsing the String as a lexical representation. 749 * 750 * <p>Parsing the lexical string representation is defined in 751 * <a href="http://www.w3.org/TR/xmlschema-2/#dateTime-order">XML Schema 1.0 Part 2, Section 3.2.[7-14].1, 752 * <em>Lexical Representation</em>.</a> 753 * 754 * <p>The string representation may not have any leading and trailing whitespaces. 755 * 756 * <p>The parsing is done field by field so that 757 * the following holds for any lexically correct String x: 758 * <pre> 759 * newXMLGregorianCalendar(x).toXMLFormat().equals(x) 760 * </pre> 761 * <p>Except for the noted lexical/canonical representation mismatches 762 * listed in <a href="http://www.w3.org/2001/05/xmlschema-errata#e2-45"> 763 * XML Schema 1.0 errata, Section 3.2.7.2</a>. 764 * 765 * @param lexicalRepresentation Lexical representation of one the eight XML Schema date/time datatypes. 766 * 767 * @return {@code XMLGregorianCalendar} created from the {@code lexicalRepresentation}. 768 * 769 * @throws IllegalArgumentException If the {@code lexicalRepresentation} is not a valid {@code XMLGregorianCalendar}. 770 * @throws NullPointerException If {@code lexicalRepresentation} is {@code null}. 771 */ 772 public abstract XMLGregorianCalendar newXMLGregorianCalendar(final String lexicalRepresentation); 773 774 /** 775 * Create an {@code XMLGregorianCalendar} from a {@link GregorianCalendar}. 776 * 777 * <table border="2" rules="all" cellpadding="2"> 778 * <thead> 779 * <tr> 780 * <th align="center" colspan="2"> 781 * Field by Field Conversion from 782 * {@link GregorianCalendar} to an {@link XMLGregorianCalendar} 783 * </th> 784 * </tr> 785 * <tr> 786 * <th>{@code java.util.GregorianCalendar} field</th> 787 * <th>{@code javax.xml.datatype.XMLGregorianCalendar} field</th> 788 * </tr> 789 * </thead> 790 * <tbody> 791 * <tr> 792 * <td>{@code ERA == GregorianCalendar.BC ? -YEAR : YEAR}</td> 793 * <td>{@link XMLGregorianCalendar#setYear(int year)}</td> 794 * </tr> 795 * <tr> 796 * <td>{@code MONTH + 1}</td> 797 * <td>{@link XMLGregorianCalendar#setMonth(int month)}</td> 798 * </tr> 799 * <tr> 800 * <td>{@code DAY_OF_MONTH}</td> 801 * <td>{@link XMLGregorianCalendar#setDay(int day)}</td> 802 * </tr> 803 * <tr> 804 * <td>{@code HOUR_OF_DAY, MINUTE, SECOND, MILLISECOND}</td> 805 * <td>{@link XMLGregorianCalendar#setTime(int hour, int minute, int second, BigDecimal fractional)}</td> 806 * </tr> 807 * <tr> 808 * <td> 809 * {@code (ZONE_OFFSET + DST_OFFSET) / (60*1000)}<br> 810 * <em>(in minutes)</em> 811 * </td> 812 * <td>{@link XMLGregorianCalendar#setTimezone(int offset)}<sup><em>*</em></sup> 813 * </td> 814 * </tr> 815 * </tbody> 816 * </table> 817 * <p><em>*</em>conversion loss of information. It is not possible to represent 818 * a {@code java.util.GregorianCalendar} daylight savings timezone id in the 819 * XML Schema 1.0 date/time datatype representation. 820 * 821 * <p>To compute the return value's {@code TimeZone} field, 822 * <ul> 823 * <li>when {@code this.getTimezone() != FIELD_UNDEFINED}, 824 * create a {@code java.util.TimeZone} with a custom timezone id 825 * using the {@code this.getTimezone()}.</li> 826 * <li>else use the {@code GregorianCalendar} default timezone value 827 * for the host is defined as specified by 828 * {@code java.util.TimeZone.getDefault()}.</li> 829 * </ul> 830 * 831 * @param cal {@code java.util.GregorianCalendar} used to create {@code XMLGregorianCalendar} 832 * 833 * @return {@code XMLGregorianCalendar} created from {@code java.util.GregorianCalendar} 834 * 835 * @throws NullPointerException If {@code cal} is {@code null}. 836 */ 837 public abstract XMLGregorianCalendar newXMLGregorianCalendar(final GregorianCalendar cal); 838 839 /** 840 * Constructor allowing for complete value spaces allowed by 841 * W3C XML Schema 1.0 recommendation for xsd:dateTime and related 842 * builtin datatypes. Note that {@code year} parameter supports 843 * arbitrarily large numbers and fractionalSecond has infinite 844 * precision. 845 * 846 * <p>A {@code null} value indicates that field is not set. 847 * 848 * @param year of {@code XMLGregorianCalendar} to be created. 849 * @param month of {@code XMLGregorianCalendar} to be created. 850 * @param day of {@code XMLGregorianCalendar} to be created. 851 * @param hour of {@code XMLGregorianCalendar} to be created. 852 * @param minute of {@code XMLGregorianCalendar} to be created. 853 * @param second of {@code XMLGregorianCalendar} to be created. 854 * @param fractionalSecond of {@code XMLGregorianCalendar} to be created. 855 * @param timezone of {@code XMLGregorianCalendar} to be created. 856 * 857 * @return {@code XMLGregorianCalendar} created from specified values. 858 * 859 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 860 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 861 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 862 * as determined by {@link XMLGregorianCalendar#isValid()}. 863 */ 864 public abstract XMLGregorianCalendar newXMLGregorianCalendar( 865 final BigInteger year, 866 final int month, 867 final int day, 868 final int hour, 869 final int minute, 870 final int second, 871 final BigDecimal fractionalSecond, 872 final int timezone); 873 874 /** 875 * Constructor of value spaces that a 876 * {@code java.util.GregorianCalendar} instance would need to convert to an 877 * {@code XMLGregorianCalendar} instance. 878 * 879 * <p>{@code XMLGregorianCalendar eon} and 880 * {@code fractionalSecond} are set to {@code null} 881 * 882 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 883 * 884 * @param year of {@code XMLGregorianCalendar} to be created. 885 * @param month of {@code XMLGregorianCalendar} to be created. 886 * @param day of {@code XMLGregorianCalendar} to be created. 887 * @param hour of {@code XMLGregorianCalendar} to be created. 888 * @param minute of {@code XMLGregorianCalendar} to be created. 889 * @param second of {@code XMLGregorianCalendar} to be created. 890 * @param millisecond of {@code XMLGregorianCalendar} to be created. 891 * @param timezone of {@code XMLGregorianCalendar} to be created. 892 * 893 * @return {@code XMLGregorianCalendar} created from specified values. 894 * 895 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 896 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 897 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 898 * as determined by {@link XMLGregorianCalendar#isValid()}. 899 */ 900 public XMLGregorianCalendar newXMLGregorianCalendar( 901 final int year, 902 final int month, 903 final int day, 904 final int hour, 905 final int minute, 906 final int second, 907 final int millisecond, 908 final int timezone) { 909 910 // year may be undefined 911 BigInteger realYear = (year != DatatypeConstants.FIELD_UNDEFINED) ? BigInteger.valueOf((long) year) : null; 912 913 // millisecond may be undefined 914 // millisecond must be >= 0 millisecond <= 1000 915 BigDecimal realMillisecond = null; // undefined value 916 if (millisecond != DatatypeConstants.FIELD_UNDEFINED) { 917 if (millisecond < 0 || millisecond > 1000) { 918 throw new IllegalArgumentException( 919 "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendar(" 920 + "int year, int month, int day, int hour, int minute, int second, int millisecond, int timezone)" 921 + "with invalid millisecond: " + millisecond 922 ); 923 } 924 925 realMillisecond = BigDecimal.valueOf((long) millisecond).movePointLeft(3); 926 } 927 928 return newXMLGregorianCalendar( 929 realYear, 930 month, 931 day, 932 hour, 933 minute, 934 second, 935 realMillisecond, 936 timezone 937 ); 938 } 939 940 /** 941 * Create a Java representation of XML Schema builtin datatype {@code date} or {@code g*}. 942 * 943 * <p>For example, an instance of {@code gYear} can be created invoking this factory 944 * with {@code month} and {@code day} parameters set to 945 * {@link DatatypeConstants#FIELD_UNDEFINED}. 946 * 947 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 948 * 949 * @param year of {@code XMLGregorianCalendar} to be created. 950 * @param month of {@code XMLGregorianCalendar} to be created. 951 * @param day of {@code XMLGregorianCalendar} to be created. 952 * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. 953 * 954 * @return {@code XMLGregorianCalendar} created from parameter values. 955 * 956 * @see DatatypeConstants#FIELD_UNDEFINED 957 * 958 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 959 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 960 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 961 * as determined by {@link XMLGregorianCalendar#isValid()}. 962 */ 963 public XMLGregorianCalendar newXMLGregorianCalendarDate( 964 final int year, 965 final int month, 966 final int day, 967 final int timezone) { 968 969 return newXMLGregorianCalendar( 970 year, 971 month, 972 day, 973 DatatypeConstants.FIELD_UNDEFINED, // hour 974 DatatypeConstants.FIELD_UNDEFINED, // minute 975 DatatypeConstants.FIELD_UNDEFINED, // second 976 DatatypeConstants.FIELD_UNDEFINED, // millisecond 977 timezone); 978 } 979 980 /** 981 * Create a Java instance of XML Schema builtin datatype {@code time}. 982 * 983 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 984 * 985 * @param hours number of hours 986 * @param minutes number of minutes 987 * @param seconds number of seconds 988 * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. 989 * 990 * @return {@code XMLGregorianCalendar} created from parameter values. 991 * 992 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 993 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 994 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 995 * as determined by {@link XMLGregorianCalendar#isValid()}. 996 * 997 * @see DatatypeConstants#FIELD_UNDEFINED 998 */ 999 public XMLGregorianCalendar newXMLGregorianCalendarTime( 1000 final int hours, 1001 final int minutes, 1002 final int seconds, 1003 final int timezone) { 1004 1005 return newXMLGregorianCalendar( 1006 DatatypeConstants.FIELD_UNDEFINED, // Year 1007 DatatypeConstants.FIELD_UNDEFINED, // Month 1008 DatatypeConstants.FIELD_UNDEFINED, // Day 1009 hours, 1010 minutes, 1011 seconds, 1012 DatatypeConstants.FIELD_UNDEFINED, //Millisecond 1013 timezone); 1014 } 1015 1016 /** 1017 * Create a Java instance of XML Schema builtin datatype time. 1018 * 1019 * <p>A {@code null} value indicates that field is not set. 1020 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 1021 * 1022 * @param hours number of hours 1023 * @param minutes number of minutes 1024 * @param seconds number of seconds 1025 * @param fractionalSecond value of {@code null} indicates that this optional field is not set. 1026 * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. 1027 * 1028 * @return {@code XMLGregorianCalendar} created from parameter values. 1029 * 1030 * @see DatatypeConstants#FIELD_UNDEFINED 1031 * 1032 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 1033 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 1034 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 1035 * as determined by {@link XMLGregorianCalendar#isValid()}. 1036 */ 1037 public XMLGregorianCalendar newXMLGregorianCalendarTime( 1038 final int hours, 1039 final int minutes, 1040 final int seconds, 1041 final BigDecimal fractionalSecond, 1042 final int timezone) { 1043 1044 return newXMLGregorianCalendar( 1045 null, // year 1046 DatatypeConstants.FIELD_UNDEFINED, // month 1047 DatatypeConstants.FIELD_UNDEFINED, // day 1048 hours, 1049 minutes, 1050 seconds, 1051 fractionalSecond, 1052 timezone); 1053 } 1054 1055 /** 1056 * Create a Java instance of XML Schema builtin datatype time. 1057 * 1058 * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set. 1059 * 1060 * @param hours number of hours 1061 * @param minutes number of minutes 1062 * @param seconds number of seconds 1063 * @param milliseconds number of milliseconds 1064 * @param timezone offset in minutes. {@link DatatypeConstants#FIELD_UNDEFINED} indicates optional field is not set. 1065 * 1066 * @return {@code XMLGregorianCalendar} created from parameter values. 1067 * 1068 * @see DatatypeConstants#FIELD_UNDEFINED 1069 * 1070 * @throws IllegalArgumentException If any individual parameter's value is outside the maximum value constraint for the field 1071 * as determined by the Date/Time Data Mapping table in {@link XMLGregorianCalendar} 1072 * or if the composite values constitute an invalid {@code XMLGregorianCalendar} instance 1073 * as determined by {@link XMLGregorianCalendar#isValid()}. 1074 */ 1075 public XMLGregorianCalendar newXMLGregorianCalendarTime( 1076 final int hours, 1077 final int minutes, 1078 final int seconds, 1079 final int milliseconds, 1080 final int timezone) { 1081 1082 // millisecond may be undefined 1083 // millisecond must be >= 0 millisecond <= 1000 1084 BigDecimal realMilliseconds = null; // undefined value 1085 if (milliseconds != DatatypeConstants.FIELD_UNDEFINED) { 1086 if (milliseconds < 0 || milliseconds > 1000) { 1087 throw new IllegalArgumentException( 1088 "javax.xml.datatype.DatatypeFactory#newXMLGregorianCalendarTime(" 1089 + "int hours, int minutes, int seconds, int milliseconds, int timezone)" 1090 + "with invalid milliseconds: " + milliseconds 1091 ); 1092 } 1093 1094 realMilliseconds = BigDecimal.valueOf((long) milliseconds).movePointLeft(3); 1095 } 1096 1097 return newXMLGregorianCalendarTime( 1098 hours, 1099 minutes, 1100 seconds, 1101 realMilliseconds, 1102 timezone 1103 ); 1104 } 1105 }