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 Vikram Aroskar
  44  * @see XMLGregorianCalendar#add(Duration)
  45  */
  46 
  47 class DurationYearMonthImpl
  48         extends DurationImpl {
  49     private static final long serialVersionUID = -4430140662861507958L;
  50 
  51     /**
  52      * <p>Constructs a new Duration object by specifying each field individually.</p>
  53      *
  54      * <p>All the parameters are optional as long as at least one field is present.
  55      * If specified, parameters have to be zero or positive.</p>
  56      *
  57      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
  58      *   of the duration is zero, this parameter will be ignored.
  59      * @param years of this <code>Duration</code>
  60      * @param months of this <code>Duration</code>
  61      *
  62      * @throws IllegalArgumentException
  63      *    If years, months parameters are all <code>null</code>. Or if any
  64      *    of those parameters are negative.
  65      */
  66     public DurationYearMonthImpl(
  67         boolean isPositive,
  68         BigInteger years,
  69         BigInteger months) {
  70 
  71         super(isPositive, years, months, null, null, null, null);
  72         convertToCanonicalYearMonth();
  73     }
  74         /**
  75          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified
  76          * <code>year</code> and <code>month</code> as defined in
  77          * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
  78          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
  79          *
  80      * <p>A {@link DatatypeConstants#FIELD_UNDEFINED} value indicates that field is not set.</p>
  81      *
  82      * @param isPositive Set to <code>false</code> to create a negative duration. When the length
  83      *   of the duration is zero, this parameter will be ignored.
  84          * @param year Year of <code>Duration</code>.
  85          * @param month Month of <code>Duration</code>.
  86          *
  87          * @throws IllegalArgumentException If the values are not a valid representation of a
  88          * <code>Duration</code>: if any of the fields (year, month) is negative.
  89          */
  90     protected DurationYearMonthImpl(
  91         final boolean isPositive,
  92         final int years,
  93         final int months) {
  94 
  95         this(isPositive,
  96             wrap(years),
  97             wrap(months));
  98 
  99 
 100     }
 101 
 102 
 103         /**
 104          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> using the specified milliseconds as defined in
 105          * <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 106          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
 107          *
 108          * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
 109          * whose lexical representation contains only year and month components.
 110          * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
 111          *
 112      * <p>Both values are set by computing their values from the specified milliseconds
 113      * and are availabe using the <code>get</code> methods of  the created {@link Duration}.
 114      * The values conform to and are defined by:</p>
 115      * <ul>
 116      *   <li>ISO 8601:2000(E) Section 5.5.3.2 Alternative format</li>
 117      *   <li><a href="http://www.w3.org/TR/xmlschema-2/#isoformats">
 118      *     W3C XML Schema 1.0 Part 2, Appendix D, ISO 8601 Date and Time Formats</a>
 119      *   </li>
 120      *   <li>{@link XMLGregorianCalendar}  Date/Time Datatype Field Mapping Between XML Schema 1.0 and Java Representation</li>
 121      * </ul>
 122      *
 123          * <p>The default start instance is defined by {@link GregorianCalendar}'s use of the start of the epoch: i.e.,
 124          * {@link java.util.Calendar#YEAR} = 1970,
 125          * {@link java.util.Calendar#MONTH} = {@link java.util.Calendar#JANUARY},
 126          * {@link java.util.Calendar#DATE} = 1, etc.
 127          * This is important as there are variations in the Gregorian Calendar,
 128          * e.g. leap years have different days in the month = {@link java.util.Calendar#FEBRUARY}
 129          * so the result of {@link Duration#getMonths()} can be influenced.</p>
 130          *
 131      * <p>Any remaining milliseconds after determining the year and month are discarded.</p>
 132          *
 133          * @param durationInMilliseconds Milliseconds of <code>Duration</code> to create.
 134          */
 135     protected DurationYearMonthImpl(long durationInMilliseconds) {
 136 
 137         super(durationInMilliseconds);
 138         convertToCanonicalYearMonth();
 139         //Any remaining milliseconds after determining the year and month are discarded.
 140         days = null;
 141         hours = null;
 142         minutes = null;
 143         seconds = null;
 144         signum = calcSignum((signum<0)?false:true);
 145     }
 146 
 147 
 148         /**
 149          * <p>Construct a <code>Duration</code> of type <code>xdt:yearMonthDuration</code> by parsing its <code>String</code> representation,
 150          * "<em>PnYnM</em>", <a href="http://www.w3.org/TR/xpath-datamodel#yearMonthDuration">
 151          *   XQuery 1.0 and XPath 2.0 Data Model, xdt:yearMonthDuration</a>.</p>
 152          *
 153          * <p>The datatype <code>xdt:yearMonthDuration</code> is a subtype of <code>xs:duration</code>
 154          * whose lexical representation contains only year and month components.
 155          * This datatype resides in the namespace {@link javax.xml.XMLConstants#W3C_XPATH_DATATYPE_NS_URI}.</p>
 156          *
 157      * <p>Both values are set and availabe from the created {@link Duration}</p>
 158          *
 159      * <p>The XML Schema specification states that values can be of an arbitrary size.
 160      * Implementations may chose not to or be incapable of supporting arbitrarily large and/or small values.
 161      * An {@link UnsupportedOperationException} will be thrown with a message indicating implementation limits
 162      * if implementation capacities are exceeded.</p>
 163      *
 164          * @param lexicalRepresentation Lexical representation of a duration.
 165          *
 166          * @throws IllegalArgumentException If <code>lexicalRepresentation</code> is not a valid representation of a <code>Duration</code> expressed only in terms of years and months.
 167          * @throws UnsupportedOperationException If implementation cannot support requested values.
 168          * @throws NullPointerException If <code>lexicalRepresentation</code> is <code>null</code>.
 169          */
 170     protected DurationYearMonthImpl(String lexicalRepresentation) {
 171         super(lexicalRepresentation);
 172         if (getDays() > 0 || getHours() > 0
 173                 || getMinutes() > 0 || getSeconds() > 0) {
 174             throw new IllegalArgumentException(
 175                     "Trying to create an xdt:yearMonthDuration with an invalid"
 176                     + " lexical representation of \"" + lexicalRepresentation
 177                     + "\", data model requires PnYnM.");
 178         }
 179         convertToCanonicalYearMonth();
 180     }
 181 
 182     /**
 183      * The value space of xs:yearMonthDuration is the set of xs:integer month values.
 184      * @return the value of yearMonthDuration
 185      */
 186     public int getValue() {
 187         return getYears() * 12 + getMonths();
 188     }
 189 
 190     private void convertToCanonicalYearMonth() {
 191         while (getMonths() >= 12)
 192         {
 193             months = months.subtract(BigInteger.valueOf(12));
 194             years = BigInteger.valueOf((long) getYears()).add(BigInteger.ONE);
 195         }
 196     }
 197 }