1 /*
   2  * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.org.apache.xerces.internal.jaxp.datatype;
  27 
  28 import java.math.BigInteger;
  29 import javax.xml.datatype.DatatypeConstants;
  30 
  31 
  32 /**
  33  * <p>Represent a subtype <code>xdt:yearMonthDuration</code> of a <code>Duration</code>
  34  * as specified in <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
  35  *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
  36  *
  37  *
  38  * <p>The DurationYearMonth object represents a period of Gregorian time,
  39  * with a lexical representation, "<em>PnYnM</em>" that contains only year and month components.
  40  * </p>
  41  *
  42  *
  43  * @author <a href="mailto:Vikram.Aroskar@Sun.COM">Vikram Aroskar</a>
  44  * @author <a href="mailto:Huizhe.wang@oracle.com">Joe Wang</a>
  45 
  46  * @see XMLGregorianCalendar#add(Duration)
  47  */
  48 
  49 class DurationYearMonthImpl
  50         extends DurationImpl {
  51     private static final long serialVersionUID = -4430140662861507958L;
  52 
  53     /**
  54      * <p>Constructs a new Duration object by specifying each field individually.</p>
  55      *
  56      * <p>All the parameters are optional as long as at least one field is present.
  57      * If specified, parameters have to be zero or positive.</p>
  58      *
  59      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
  60      *   of the duration is zero, this parameter will be ignored.
  61      * @param years of this <code>Duration</code>
  62      * @param months of this <code>Duration</code>
  63      *
  64      * @throws IllegalArgumentException
  65      *    If years, months parameters are all <code>null</code>. Or if any
  66      *    of those parameters are negative.
  67      */
  68     public DurationYearMonthImpl(
  69         boolean isPositive,
  70         BigInteger years,
  71         BigInteger months) {
  72 
  73         super(isPositive, years, months, null, null, null, null);
  74         convertToCanonicalYearMonth();
  75     }
  76         /**
  77          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
  78          * <code>year</code> and <code>month</code> as defined in
  79          * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
  80          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
  81          *
  82      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
  83      *
  84      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
  85      *   of the duration is zero, this parameter will be ignored.
  86          * @param year Year of <code>Duration</code>.
  87          * @param month Month of <code>Duration</code>.
  88          *
  89          * @throws IllegalArgumentException If the values are not a valid representation of a
  90          * <code>Duration</code>: if any of the fields (year, month) is negative.
  91          */
  92     protected DurationYearMonthImpl(
  93         final boolean isPositive,
  94         final int years,
  95         final int months) {
  96 
  97         this(isPositive,
  98             wrap(years),
  99             wrap(months));
 100 
 101 
 102     }
 103 
 104 
 105         /**
 106          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
 107          * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 108          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
 109          *
 110          * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
 111          * whose lexical representation contains only year and month components.
 112          * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
 113          *
 114      * <p>Both values are set by computing their values from the specified milliseconds
 115      * and are availabe using the <code>get</code> methods of  the created {@link Duration}.
 116      * The values conform to and are defined by:</p>
 117      * <ul>
 118      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
 119      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
 120      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
 121      *   </li>
 122      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
 123      * </ul>
 124      *
 125          * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
 126          * {@link java.util.Calendar#YEAR} = 1970,
 127          * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
 128          * {@link java.util.Calendar#DATE} = 1, etc.
 129          * This is important as there are variations in the Gregorian Calendar,
 130          * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
 131          * so the result of {@link Duration#getMonths()} can be influenced.</p>
 132          *
 133      * <p>Any remaining milliseconds after determining the year and month are discarded.</p>
 134          *
 135          * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
 136          */
 137     protected DurationYearMonthImpl(long durationInMilliseconds) {
 138 
 139         super(durationInMilliseconds);
 140         convertToCanonicalYearMonth();
 141         //Any remaining milliseconds after determining the year and month are discarded.
 142         days = null;
 143         hours = null;
 144         minutes = null;
 145         seconds = null;
 146         signum = calcSignum((signum<0)?false:true);
 147     }
 148 
 149 
 150         /**
 151          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
 152          * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 153          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
 154          *
 155          * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
 156          * whose lexical representation contains only year and month components.
 157          * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
 158          *
 159      * <p>Both values are set and availabe from the created {@link Duration}</p>
 160          *
 161      * <p>The XML Schema specification states that values can be of an arbitrary size.
 162      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 163      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 164      * if implementation capacities are exceeded.</p>
 165      *
 166          * @param lexicalRepresentation Lexical representation of a duration.
 167          *
 168          * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of years and months.
 169          * @throws UnsupportedOperationException If implementation cannot support requested values.
 170          * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
 171          */
 172     protected DurationYearMonthImpl(String lexicalRepresentation) {
 173         super(lexicalRepresentation);
 174         if (getDays() > 0 || getHours() > 0
 175                 || getMinutes() > 0 || getSeconds() > 0) {
 176             throw new IllegalArgumentException(
 177                     "Trying to create an xdt:yearMonthDuration with an invalid"
 178                     + " lexical representation of \"" + lexicalRepresentation
 179                     + "\", data model requires PnYnM.");
 180         }
 181         convertToCanonicalYearMonth();
 182     }
 183 
 184     /**
 185      * The value space of xs:yearMonthDuration is the set of xs:integer month values.
 186      * @return the value of yearMonthDuration
 187      */
 188     public int getValue() {
 189         return getYears() * 12 + getMonths();
 190     }
 191 
 192     private void convertToCanonicalYearMonth() {
 193         while (getMonths() >= 12)
 194         {
 195             months = months.subtract(BigInteger.valueOf(12));
 196             years = BigInteger.valueOf((long) getYears()).add(BigInteger.ONE);
 197         }
 198     }
 199 }