1320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/*
2320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one or more
3320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * contributor license agreements.  See the NOTICE file distributed with
4320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * this work for additional information regarding copyright ownership.
5320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * The ASF licenses this file to You under the Apache License, Version 2.0
6320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * (the "License"); you may not use this file except in compliance with
7320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the License.  You may obtain a copy of the License at
8320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
9320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
10320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
11320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Unless required by applicable law or agreed to in writing, software
12320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
13320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * See the License for the specific language governing permissions and
15320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * limitations under the License.
16320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */
17320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
18320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson//$Id: Duration.java 759828 2009-03-30 01:26:29Z mrglavas $
19320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
20320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonpackage javax.xml.datatype;
21320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
22320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.math.BigDecimal;
23320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.math.BigInteger;
24320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Calendar;
25320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.Date;
26320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport java.util.GregorianCalendar;
27320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonimport javax.xml.namespace.QName;
28320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
29320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson/**
30320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Immutable representation of a time span as defined in
31320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the W3C XML Schema 1.0 specification.</p>
32f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
33320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>A Duration object represents a period of Gregorian time,
34320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * which consists of six fields (years, months, days, hours,
35320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * minutes, and seconds) plus a sign (+/-) field.</p>
36f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
37320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>The first five fields have non-negative (>=0) integers or null
38320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * (which represents that the field is not set),
39320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * and the seconds field has a non-negative decimal or null.
40f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * A negative sign indicates a negative duration.</p>
41f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
42320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>This class provides a number of methods that make it easy
43320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * to use for the duration datatype of XML Schema 1.0 with
44320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the errata.</p>
45f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
46320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <h2>Order relationship</h2>
47320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Duration objects only have partial order, where two values A and B
48320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * maybe either:</p>
49320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <ol>
50320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *  <li>A&lt;B (A is shorter than B)
51320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *  <li>A&gt;B (A is longer than B)
52320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *  <li>A==B   (A and B are of the same duration)
53320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *  <li>A&lt;>B (Comparison between A and B is indeterminate)
54320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * </ol>
55320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson *
56320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>For example, 30 days cannot be meaningfully compared to one month.
57320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * The {@link #compare(Duration duration)} method implements this
58320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * relationship.</p>
59f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
60320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>See the {@link #isLongerThan(Duration)} method for details about
61320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the order relationship among <code>Duration</code> objects.</p>
62f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
63320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <h2>Operations over Duration</h2>
64320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>This class provides a set of basic arithmetic operations, such
65320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * as addition, subtraction and multiplication.
66320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Because durations don't have total order, an operation could
67320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * fail for some combinations of operations. For example, you cannot
68320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * subtract 15 days from 1 month. See the javadoc of those methods
69320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * for detailed conditions where this could happen.</p>
70f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
71320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>Also, division of a duration by a number is not provided because
72320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * the <code>Duration</code> class can only deal with finite precision
73f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * decimal numbers. For example, one cannot represent 1 sec divided by 3.</p>
74f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
75320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>However, you could substitute a division by 3 with multiplying
76320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * by numbers such as 0.3 or 0.333.</p>
77f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
78320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <h2>Range of allowed values</h2>
79320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * <p>
80320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * Because some operations of <code>Duration</code> rely on {@link Calendar}
81320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * even though {@link Duration} can hold very large or very small values,
82320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * some of the methods may not work correctly on such <code>Duration</code>s.
83320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * The impacted methods document their dependency on {@link Calendar}.
84f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
85f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes *
86320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Joseph.Fialli@Sun.COM">Joseph Fialli</a>
87320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
88320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
89f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * @version $Revision: 759828 $, $Date: 2009-03-29 18:26:29 -0700 (Sun, 29 Mar 2009) $
90320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @see XMLGregorianCalendar#add(Duration)
91320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson * @since 1.5
92320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson */
93320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilsonpublic abstract class   Duration {
94320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
95320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
96f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * <p>Return the name of the XML Schema date/time type that this instance
97320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * maps to. Type is computed based on fields that are set,
98320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * i.e. {@link #isSet(DatatypeConstants.Field field)} == <code>true</code>.</p>
99320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
100320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <table border="2" rules="all" cellpadding="2">
101320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <thead>
102320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     <tr>
103320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <th align="center" colspan="7">
104320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
105320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *         <i>(timezone is optional for all date/time datatypes)</i>
106320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       </th>
107320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     </tr>
108320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   </thead>
109320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <tbody>
110320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     <tr>
111320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>Datatype</td>
112320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>year</td>
113320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>month</td>
114320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>day</td>
115320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>hour</td>
116320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>minute</td>
117320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>second</td>
118320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     </tr>
119320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     <tr>
120320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>{@link DatatypeConstants#DURATION}</td>
121320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
122320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
123320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
124320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
125320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
126320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
127320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     </tr>
128320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     <tr>
129320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>{@link DatatypeConstants#DURATION_DAYTIME}</td>
130320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
131320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
132320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
133320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
134320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
135320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
136320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     </tr>
137320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     <tr>
138320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>{@link DatatypeConstants#DURATION_YEARMONTH}</td>
139320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
140320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td>X</td>
141320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
142320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
143320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
144320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *       <td></td>
145320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     </tr>
146320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   </tbody>
147320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </table>
148f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
149320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return one of the following constants:
150320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   {@link DatatypeConstants#DURATION},
151320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   {@link DatatypeConstants#DURATION_DAYTIME} or
152320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   {@link DatatypeConstants#DURATION_YEARMONTH}.
153f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
154320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws IllegalStateException If the combination of set fields does not match one of the XML Schema date/time datatypes.
155320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
156320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public QName getXMLSchemaType() {
157320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
158320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean yearSet = isSet(DatatypeConstants.YEARS);
159320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean monthSet = isSet(DatatypeConstants.MONTHS);
160320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean daySet = isSet(DatatypeConstants.DAYS);
161320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean hourSet = isSet(DatatypeConstants.HOURS);
162320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean minuteSet = isSet(DatatypeConstants.MINUTES);
163320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        boolean secondSet = isSet(DatatypeConstants.SECONDS);
164320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
165320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // DURATION
166320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (yearSet
167320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && monthSet
168320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && daySet
169320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && hourSet
170320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && minuteSet
171320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && secondSet) {
172320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return DatatypeConstants.DURATION;
173320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
174320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
175320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // DURATION_DAYTIME
176320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (!yearSet
177320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && !monthSet
178320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && daySet
179320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && hourSet
180320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && minuteSet
181320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && secondSet) {
182320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return DatatypeConstants.DURATION_DAYTIME;
183320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
184320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
185320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // DURATION_YEARMONTH
186320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (yearSet
187320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && monthSet
188320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && !daySet
189320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && !hourSet
190320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && !minuteSet
191320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                && !secondSet) {
192320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return DatatypeConstants.DURATION_YEARMONTH;
193320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
194320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
195320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // nothing matches
196320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        throw new IllegalStateException(
197320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                "javax.xml.datatype.Duration#getXMLSchemaType():"
198320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " this Duration does not match one of the XML Schema date/time datatypes:"
199320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " year set = " + yearSet
200320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " month set = " + monthSet
201320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " day set = " + daySet
202320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " hour set = " + hourSet
203320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " minute set = " + minuteSet
204320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                + " second set = " + secondSet
205320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        );
206320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
207320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
208320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
209320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Returns the sign of this duration in -1,0, or 1.
210f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
211320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
212320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      -1 if this duration is negative, 0 if the duration is zero,
213320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      and 1 if the duration is positive.
214320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
215320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract int getSign();
216320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
217320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
218320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Get the years value of this <code>Duration</code> as an <code>int</code> or <code>0</code> if not present.</p>
219f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
220320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p><code>getYears()</code> is a convenience method for
221320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)}.</p>
222f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
223320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>As the return value is an <code>int</code>, an incorrect value will be returned for <code>Duration</code>s
224320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * with years that go beyond the range of an <code>int</code>.
225320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Use {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)} to avoid possible loss of precision.</p>
226f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
227320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return If the years field is present, return its value as an <code>int</code>, else return <code>0</code>.
228320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
229320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getYears() {
230320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.YEARS);
231320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
232320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
233320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
234320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Obtains the value of the MONTHS field as an integer value,
235320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * or 0 if not present.
236f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
237320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method works just like {@link #getYears()} except
238320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * that this method works on the MONTHS field.
239f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
240320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Months of this <code>Duration</code>.
241320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
242320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getMonths() {
243320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.MONTHS);
244320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
245320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
246320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
247320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Obtains the value of the DAYS field as an integer value,
248320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * or 0 if not present.
249f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
250320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method works just like {@link #getYears()} except
251320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * that this method works on the DAYS field.
252f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
253320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Days of this <code>Duration</code>.
254320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
255320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getDays() {
256320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.DAYS);
257320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
258320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
259320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
260320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Obtains the value of the HOURS field as an integer value,
261320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * or 0 if not present.
262f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
263320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method works just like {@link #getYears()} except
264320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * that this method works on the HOURS field.
265f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
266320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Hours of this <code>Duration</code>.
267f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
268320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
269320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getHours() {
270320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.HOURS);
271320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
272320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
273320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
274320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Obtains the value of the MINUTES field as an integer value,
275320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * or 0 if not present.
276f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
277320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method works just like {@link #getYears()} except
278320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * that this method works on the MINUTES field.
279f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
280320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Minutes of this <code>Duration</code>.
281f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
282320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
283320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getMinutes() {
284320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.MINUTES);
285320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
286320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
287320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
288320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Obtains the value of the SECONDS field as an integer value,
289320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * or 0 if not present.
290f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
291320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method works just like {@link #getYears()} except
292320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * that this method works on the SECONDS field.
293f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
294320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return seconds in the integer value. The fraction of seconds
295320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   will be discarded (for example, if the actual value is 2.5,
296320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   this method returns 2)
297320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
298320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public int getSeconds() {
299320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getFieldValueAsInt(DatatypeConstants.SECONDS);
300320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
301320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
302320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
303320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Returns the length of the duration in milliseconds.</p>
304f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
305320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>If the seconds field carries more digits than millisecond order,
306f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * those will be simply discarded (or in other words, rounded to zero.)
307320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * For example, for any Calendar value <code>x</code>,</p>
308320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
309320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
310320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
311320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
312f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
313320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
314320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Note that this method uses the {@link #addTo(Calendar)} method,
315320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * which may work incorrectly with <code>Duration</code> objects with
316320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * very large values in its fields. See the {@link #addTo(Calendar)}
317320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * method for details.
318f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
319320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param startInstant
320320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      The length of a month/year varies. The <code>startInstant</code> is
321320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      used to disambiguate this variance. Specifically, this method
322320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      returns the difference between <code>startInstant</code> and
323320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      <code>startInstant+duration</code>
324f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
325320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return milliseconds between <code>startInstant</code> and
326320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <code>startInstant</code> plus this <code>Duration</code>
327320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
328f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @throws NullPointerException if <code>startInstant</code> parameter
329320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * is null.
330f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
331320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
332320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public long getTimeInMillis(final Calendar startInstant) {
333320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Calendar cal = (Calendar) startInstant.clone();
334320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        addTo(cal);
335320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getCalendarTimeInMillis(cal)
336320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        - getCalendarTimeInMillis(startInstant);
337320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
338320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
339320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
340320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Returns the length of the duration in milliseconds.</p>
341f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
342320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>If the seconds field carries more digits than millisecond order,
343320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * those will be simply discarded (or in other words, rounded to zero.)
344f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * For example, for any <code>Date</code> value <code>x</code>,</p>
345320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
346320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
347320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
348320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
349f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
350320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
351320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Note that this method uses the {@link #addTo(Date)} method,
352320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * which may work incorrectly with <code>Duration</code> objects with
353320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * very large values in its fields. See the {@link #addTo(Date)}
354320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * method for details.
355f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
356320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param startInstant
357320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      The length of a month/year varies. The <code>startInstant</code> is
358320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      used to disambiguate this variance. Specifically, this method
359320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      returns the difference between <code>startInstant</code> and
360320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      <code>startInstant+duration</code>.
361f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
362320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
363320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If the startInstant parameter is null.
364f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
365320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return milliseconds between <code>startInstant</code> and
366320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <code>startInstant</code> plus this <code>Duration</code>
367320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
368320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #getTimeInMillis(Calendar)
369320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
370320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public long getTimeInMillis(final Date startInstant) {
371320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Calendar cal = new GregorianCalendar();
372320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        cal.setTime(startInstant);
373320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        this.addTo(cal);
374320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return getCalendarTimeInMillis(cal) - startInstant.getTime();
375320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
376320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
377320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
378f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Gets the value of a field.
379f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
380320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Fields of a duration object may contain arbitrary large value.
381320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Therefore this method is designed to return a {@link Number} object.
382f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
383320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned
384320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * number will be a non-negative integer. In case of seconds,
385320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the returned number may be a non-negative decimal value.
386f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
387320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param field
388320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
389320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      MINUTES, or SECONDS.)
390320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
391320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If the specified field is present, this method returns
392320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      a non-null non-negative {@link Number} object that
393320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      represents its value. If it is not present, return null.
394320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method
395320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      returns a {@link java.math.BigInteger} object. For SECONDS, this
396f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *      method returns a {@link java.math.BigDecimal}.
397f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
398320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException If the <code>field</code> is <code>null</code>.
399320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
400320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract Number getField(final DatatypeConstants.Field field);
401f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes
402320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
403320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Gets the value of a field as an <code>int</code>.
404f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
405f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @param field
406320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
407320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      MINUTES, or SECONDS.)
408f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @return
409f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *      If the field is present, return its value as an <code>int</code>,
410320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      else return <code>0</code>.
411320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
412320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private int getFieldValueAsInt(final DatatypeConstants.Field field) {
413320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Number n = getField(field);
414320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (n != null) {
415320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return n.intValue();
416320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
417320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return 0;
418320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
419320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
420320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
421320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Checks if a field is set.
422f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
423320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * A field of a duration object may or may not be present.
424320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This method can be used to test if a field is present.
425f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
426320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param field
427320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
428320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      MINUTES, or SECONDS.)
429320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
430320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      true if the field is present. false if not.
431f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
432320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
433320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If the field parameter is null.
434320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
435320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract boolean isSet(final DatatypeConstants.Field field);
436320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
437320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
438320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Computes a new duration whose value is <code>this+rhs</code>.</p>
439f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
440320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>For example,</p>
441320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
442320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 day" + "-3 days" = "-2 days"
443320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 year" + "1 day" = "1 year and 1 day"
444320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "-(1 hour,50 minutes)" + "-20 minutes" = "-(1 hours,70 minutes)"
445320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "15 hours" + "-3 days" = "-(2 days,9 hours)"
446320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 year" + "-1 day" = IllegalStateException
447320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
448f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
449320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
450320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * there are cases where the operation fails in
451f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * {@link IllegalStateException}.</p>
452f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
453320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
454320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Formally, the computation is defined as follows.</p>
455320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
456320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Firstly, we can assume that two <code>Duration</code>s to be added
457320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * are both positive without losing generality (i.e.,
458320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>(-X)+Y=Y-X</code>, <code>X+(-Y)=X-Y</code>,
459320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>(-X)+(-Y)=-(X+Y)</code>)
460f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
461320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
462f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * Addition of two positive <code>Duration</code>s are simply defined as
463320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * field by field addition where missing fields are treated as 0.
464320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
465320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * A field of the resulting <code>Duration</code> will be unset if and
466f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * only if respective fields of two input <code>Duration</code>s are unset.
467320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
468320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Note that <code>lhs.add(rhs)</code> will be always successful if
469320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>lhs.signum()*rhs.signum()!=-1</code> or both of them are
470320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * normalized.</p>
471f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
472320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param rhs <code>Duration</code> to add to this <code>Duration</code>
473f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
474320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
475320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      non-null valid Duration object.
476f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
477320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
478320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If the rhs parameter is null.
479320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws IllegalStateException
480320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If two durations cannot be meaningfully added. For
481320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      example, adding negative one day to one month causes
482320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      this exception.
483f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
484f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
485320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #subtract(Duration)
486320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
487320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract Duration add(final Duration rhs);
488320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
489320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
490320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Adds this duration to a {@link Calendar} object.
491f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
492320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
493320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Calls {@link java.util.Calendar#add(int,int)} in the
494320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS
495320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * if those fields are present. Because the {@link Calendar} class
496320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * uses int to hold values, there are cases where this method
497320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * won't work correctly (for example if values of fields
498f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * exceed the range of int.)
499320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </p>
500f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
501320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
502320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Also, since this duration class is a Gregorian duration, this
503320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * method will not work correctly if the given {@link Calendar}
504f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * object is based on some other calendar systems.
505320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </p>
506f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
507320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
508320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Any fractional parts of this <code>Duration</code> object
509320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * beyond milliseconds will be simply ignored. For example, if
510320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * this duration is "P1.23456S", then 1 is added to SECONDS,
511f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * 234 is added to MILLISECONDS, and the rest will be unused.
512320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </p>
513f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
514320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
515320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Note that because {@link Calendar#add(int, int)} is using
516320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <tt>int</tt>, <code>Duration</code> with values beyond the
517320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * range of <tt>int</tt> in its fields
518320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * will cause overflow/underflow to the given {@link Calendar}.
519320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * {@link XMLGregorianCalendar#add(Duration)} provides the same
520320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * basic operation as this method while avoiding
521320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the overflow/underflow issues.
522f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
523320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param calendar
524320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      A calendar object whose value will be modified.
525320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
526320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      if the calendar parameter is null.
527320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
528320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract void addTo(Calendar calendar);
529320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
530320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
531320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Adds this duration to a {@link Date} object.
532f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
533320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
534320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * The given date is first converted into
535320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * a {@link java.util.GregorianCalendar}, then the duration
536320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * is added exactly like the {@link #addTo(Calendar)} method.
537f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
538320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
539320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * The updated time instant is then converted back into a
540320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * {@link Date} object and used to update the given {@link Date} object.
541f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
542320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
543320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * This somewhat redundant computation is necessary to unambiguously
544320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * determine the duration of months and years.
545f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
546320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param date
547320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      A date object whose value will be modified.
548320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
549320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      if the date parameter is null.
550320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
551320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public void addTo(Date date) {
552320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
553320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        // check data parameter
554320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (date == null) {
55586acc043d3334651ee26c65467d78d6cefedd397Kenny Root            throw new NullPointerException("date == null");
556320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
557320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
558320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        Calendar cal = new GregorianCalendar();
559f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        cal.setTime(date);
560320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        this.addTo(cal);
561320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        date.setTime(getCalendarTimeInMillis(cal));
562320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
563320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
564320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
565320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Computes a new duration whose value is <code>this-rhs</code>.</p>
566f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
567320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>For example:</p>
568320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
569320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 day" - "-3 days" = "4 days"
570320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 year" - "1 day" = IllegalStateException
571320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "-(1 hour,50 minutes)" - "-20 minutes" = "-(1hours,30 minutes)"
572320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "15 hours" - "-3 days" = "3 days and 15 hours"
573320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "1 year" - "-1 day" = "1 year and 1 day"
574320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
575f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
576320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
577f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * there are cases where the operation fails in {@link IllegalStateException}.</p>
578f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
579320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Formally the computation is defined as follows.
580320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * First, we can assume that two <code>Duration</code>s are both positive
581320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * without losing generality.  (i.e.,
582320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>(-X)-Y=-(X+Y)</code>, <code>X-(-Y)=X+Y</code>,
583320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>(-X)-(-Y)=-(X-Y)</code>)</p>
584f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
585320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Then two durations are subtracted field by field.
586320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * If the sign of any non-zero field <tt>F</tt> is different from
587320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the sign of the most significant field,
588320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * 1 (if <tt>F</tt> is negative) or -1 (otherwise)
589320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * will be borrowed from the next bigger unit of <tt>F</tt>.</p>
590f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
591320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>This process is repeated until all the non-zero fields have
592f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * the same sign.</p>
593f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
594320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>If a borrow occurs in the days field (in other words, if
595320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the computation needs to borrow 1 or -1 month to compensate
596320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * days), then the computation fails by throwing an
597320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * {@link IllegalStateException}.</p>
598f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
599320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param rhs <code>Duration</code> to subtract from this <code>Duration</code>.
600f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
601320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return New <code>Duration</code> created from subtracting <code>rhs</code> from this <code>Duration</code>.
602f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
603320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws IllegalStateException
604320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If two durations cannot be meaningfully subtracted. For
605320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      example, subtracting one day from one month causes
606320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      this exception.
607f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
608320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException
609320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      If the rhs parameter is null.
610f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
611320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #add(Duration)
612320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
613320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public Duration subtract(final Duration rhs) {
614320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return add(rhs.negate());
615320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
616320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
617320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
618320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Computes a new duration whose value is <code>factor</code> times
619320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * longer than the value of this duration.</p>
620f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
621320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>This method is provided for the convenience.
622320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * It is functionally equivalent to the following code:</p>
623320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
624320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * multiply(new BigDecimal(String.valueOf(factor)))
625320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
626f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
627320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param factor Factor times longer of new <code>Duration</code> to create.
628f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
629320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return New <code>Duration</code> that is <code>factor</code>times longer than this <code>Duration</code>.
630f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
631320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #multiply(BigDecimal)
632320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
633320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public Duration multiply(int factor) {
634320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return multiply(BigDecimal.valueOf(factor));
635320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
636320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
637320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
638320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Computes a new duration whose value is <code>factor</code> times
639320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * longer than the value of this duration.
640f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
641320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
642320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * For example,
643320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
644320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "P1M" (1 month) * "12" = "P12M" (12 months)
645320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "PT1M" (1 min) * "0.3" = "PT18S" (18 seconds)
646320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "P1M" (1 month) * "1.5" = IllegalStateException
647320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
648f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
649320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
650320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Since the <code>Duration</code> class is immutable, this method
651320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * doesn't change the value of this object. It simply computes
652320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * a new Duration object and returns it.
653f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
654320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
655320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * The operation will be performed field by field with the precision
656320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * of {@link BigDecimal}. Since all the fields except seconds are
657320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * restricted to hold integers,
658320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * any fraction produced by the computation will be
659320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * carried down toward the next lower unit. For example,
660320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * if you multiply "P1D" (1 day) with "0.5", then it will be 0.5 day,
661320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * which will be carried down to "PT12H" (12 hours).
662320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * When fractions of month cannot be meaningfully carried down
663320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * to days, or year to months, this will cause an
664f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * {@link IllegalStateException} to be thrown.
665320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * For example if you multiple one month by 0.5.</p>
666f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
667320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
668320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * To avoid {@link IllegalStateException}, use
669320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the {@link #normalizeWith(Calendar)} method to remove the years
670320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * and months fields.
671f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
672320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param factor to multiply by
673f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
674320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
675320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      returns a non-null valid <code>Duration</code> object
676320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
677f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @throws IllegalStateException if operation produces fraction in
678320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * the months field.
679320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
680f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @throws NullPointerException if the <code>factor</code> parameter is
681320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <code>null</code>.
682320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
683320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
684320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract Duration multiply(final BigDecimal factor);
685320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
686320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
687320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Returns a new <code>Duration</code> object whose
688320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * value is <code>-this</code>.
689f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
690320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>
691320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Since the <code>Duration</code> class is immutable, this method
692320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * doesn't change the value of this object. It simply computes
693320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * a new Duration object and returns it.
694f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
695320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
696320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      always return a non-null valid <code>Duration</code> object.
697320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
698f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes    public abstract Duration negate();
699320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
700320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
701320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Converts the years and months fields into the days field
702320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * by using a specific time instant as the reference point.</p>
703f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
704320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>For example, duration of one month normalizes to 31 days
705320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * given the start time instance "July 8th 2003, 17:40:32".</p>
706f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
707320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Formally, the computation is done as follows:</p>
708320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <ol>
709320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *  <li>the given Calendar object is cloned</li>
710320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *  <li>the years, months and days fields will be added to the {@link Calendar} object
711f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *      by using the {@link Calendar#add(int,int)} method</li>
712320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *  <li>the difference between the two Calendars in computed in milliseconds and converted to days,
713320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *     if a remainder occurs due to Daylight Savings Time, it is discarded</li>
714320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *  <li>the computed days, along with the hours, minutes and seconds
715320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      fields of this duration object is used to construct a new
716320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      Duration object.</li>
717320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </ol>
718f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
719320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Note that since the Calendar class uses <code>int</code> to
720320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * hold the value of year and month, this method may produce
721320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * an unexpected result if this duration object holds
722320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * a very large value in the years or months fields.</p>
723320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
724320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param startTimeInstant <code>Calendar</code> reference point.
725f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
726320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return <code>Duration</code> of years and months of this <code>Duration</code> as days.
727f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
728320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException If the startTimeInstant parameter is null.
729320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
730320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract Duration normalizeWith(final Calendar startTimeInstant);
731320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
732320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
733320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Partial order relation comparison with this <code>Duration</code> instance.</p>
734f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
735320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Comparison result must be in accordance with
736320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <a href="http://www.w3.org/TR/xmlschema-2/#duration-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2,
737320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <i>Order relation on duration</i></a>.</p>
738f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
739320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Return:</p>
740320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <ul>
741320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <li>{@link DatatypeConstants#LESSER} if this <code>Duration</code> is shorter than <code>duration</code> parameter</li>
742320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <li>{@link DatatypeConstants#EQUAL} if this <code>Duration</code> is equal to <code>duration</code> parameter</li>
743320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <li>{@link DatatypeConstants#GREATER} if this <code>Duration</code> is longer than <code>duration</code> parameter</li>
744320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   <li>{@link DatatypeConstants#INDETERMINATE} if a conclusive partial order relation cannot be determined</li>
745320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </ul>
746320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
747320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param duration to compare
748f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
749320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return the relationship between <code>this</code> <code>Duration</code>and <code>duration</code> parameter as
750320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER}
751320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   or {@link DatatypeConstants#INDETERMINATE}.
752f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
753320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws UnsupportedOperationException If the underlying implementation
754320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
755320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   arbitrarily large/small/precise values, the request may be beyond the
756320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   implementations capability.
757f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @throws NullPointerException if <code>duration</code> is <code>null</code>.
758320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
759320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #isShorterThan(Duration)
760320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #isLongerThan(Duration)
761320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
762320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract int compare(final Duration duration);
763320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
764320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
765320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Checks if this duration object is strictly longer than
766320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * another <code>Duration</code> object.</p>
767f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
768f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * <p>Duration X is "longer" than Y if and only if X>Y
769320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * as defined in the section 3.2.6.2 of the XML Schema 1.0
770320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * specification.</p>
771f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
772320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>For example, "P1D" (one day) > "PT12H" (12 hours) and
773f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * "P2Y" (two years) > "P23M" (23 months).</p>
774f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
775320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param duration <code>Duration</code> to test this <code>Duration</code> against.
776f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
777320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws UnsupportedOperationException If the underlying implementation
778320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
779320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   arbitrarily large/small/precise values, the request may be beyond the
780320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   implementations capability.
781320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException If <code>duration</code> is null.
782f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
783320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
784320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      true if the duration represented by this object
785320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      is longer than the given duration. false otherwise.
786f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
787320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #isShorterThan(Duration)
788320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #compare(Duration duration)
789320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
790320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public boolean isLongerThan(final Duration duration) {
791320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return compare(duration) == DatatypeConstants.GREATER;
792320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
793320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
794320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
795320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Checks if this duration object is strictly shorter than
796320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * another <code>Duration</code> object.</p>
797f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
798320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param duration <code>Duration</code> to test this <code>Duration</code> against.
799f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
800320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return <code>true</code> if <code>duration</code> parameter is shorter than this <code>Duration</code>,
801f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *   else <code>false</code>.
802f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
803320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws UnsupportedOperationException If the underlying implementation
804320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
805320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   arbitrarily large/small/precise values, the request may be beyond the
806320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   implementations capability.
807320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws NullPointerException if <code>duration</code> is null.
808320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
809320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #isLongerThan(Duration duration)
810320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #compare(Duration duration)
811320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
812320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public boolean isShorterThan(final Duration duration) {
813320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return compare(duration) == DatatypeConstants.LESSER;
814320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
815320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
816320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
817320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Checks if this duration object has the same duration
818320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * as another <code>Duration</code> object.</p>
819f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
820320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>For example, "P1D" (1 day) is equal to "PT24H" (24 hours).</p>
821f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
822320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Duration X is equal to Y if and only if time instant
823320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * t+X and t+Y are the same for all the test time instants
824f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * specified in the section 3.2.6.2 of the XML Schema 1.0
825320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * specification.</p>
826f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
827320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Note that there are cases where two <code>Duration</code>s are
828320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * "incomparable" to each other, like one month and 30 days.
829320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * For example,</p>
830320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
831320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * !new Duration("P1M").isShorterThan(new Duration("P30D"))
832320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * !new Duration("P1M").isLongerThan(new Duration("P30D"))
833320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * !new Duration("P1M").equals(new Duration("P30D"))
834320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
835f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
836320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param duration
837320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      A non-null valid <code>Duration</code> object.
838f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
839320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return
840320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      <code>true</code> if this duration is the same length as
841320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *         <code>duration</code>.
842320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *      <code>false</code> if <code>duration</code> is not a
843320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *         <code>Duration</code> object, is <code>null</code>,
844320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *         or its length is different from this duration.
845f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
846320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @throws UnsupportedOperationException If the underlying implementation
847320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   cannot reasonably process the request, e.g. W3C XML Schema allows for
848320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   arbitrarily large/small/precise values, the request may be beyond the
849320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *   implementations capability.
850320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     *
851320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @see #compare(Duration duration)
852320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
853320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public boolean equals(final Object duration) {
854320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (duration == this) {
855320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return true;
856320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
857320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (duration instanceof Duration) {
858320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return compare((Duration) duration) == DatatypeConstants.EQUAL;
859320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
860320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return false;
861320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
862320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
863320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
864320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Returns a hash code consistent with the definition of the equals method.
865f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
866f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @see Object#hashCode()
867320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
868320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public abstract int hashCode();
869320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
870320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
871320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Returns a <code>String</code> representation of this <code>Duration</code> <code>Object</code>.</p>
872f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
873320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>The result is formatted according to the XML Schema 1.0 specification and can be always parsed back later into the
874320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * equivalent <code>Duration</code> <code>Object</code> by {@link DatatypeFactory#newDuration(String  lexicalRepresentation)}.</p>
875f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
876320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Formally, the following holds for any <code>Duration</code>
877f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * <code>Object</code> x:</p>
878320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <pre>
879320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * new Duration(x.toString()).equals(x)
880320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * </pre>
881f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
882320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return A non-<code>null</code> valid <code>String</code> representation of this <code>Duration</code>.
883320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
884320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    public String toString() {
8857f0c06f737b6f1f6b3a5bb30111f95dd0ca586a2Brian Carlstrom        StringBuilder buf = new StringBuilder();
886320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
887320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (getSign() < 0) {
888320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append('-');
889320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
890320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        buf.append('P');
891320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
892320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigInteger years = (BigInteger) getField(DatatypeConstants.YEARS);
893320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (years != null) {
894320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append(years).append('Y');
895320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
896320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
897320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigInteger months = (BigInteger) getField(DatatypeConstants.MONTHS);
898320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (months != null) {
899320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append(months).append('M');
900320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
901320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
902320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigInteger days = (BigInteger) getField(DatatypeConstants.DAYS);
903320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (days != null) {
904320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append(days).append('D');
905320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
906320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
907320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigInteger hours = (BigInteger) getField(DatatypeConstants.HOURS);
908320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigInteger minutes = (BigInteger) getField(DatatypeConstants.MINUTES);
909320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        BigDecimal seconds = (BigDecimal) getField(DatatypeConstants.SECONDS);
910320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (hours != null || minutes != null || seconds != null) {
911320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append('T');
912320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (hours != null) {
913320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                buf.append(hours).append('H');
914320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
915320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (minutes != null) {
916320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                buf.append(minutes).append('M');
917320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
918320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            if (seconds != null) {
919320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                buf.append(toString(seconds)).append('S');
920320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
921320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
922320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
923320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return buf.toString();
924320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
925320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
926320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
927320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Turns {@link BigDecimal} to a string representation.</p>
928f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
929320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Due to a behavior change in the {@link BigDecimal#toString()}
930320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * method in JDK1.5, this had to be implemented here.</p>
931f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
932320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param bd <code>BigDecimal</code> to format as a <code>String</code>
933f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
934f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     * @return  <code>String</code> representation of <code>BigDecimal</code>
935320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
936320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private String toString(BigDecimal bd) {
937320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        String intString = bd.unscaledValue().toString();
938320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        int scale = bd.scale();
939320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
940320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (scale == 0) {
941320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return intString;
942320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
943320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
944320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        /* Insert decimal point */
9457f0c06f737b6f1f6b3a5bb30111f95dd0ca586a2Brian Carlstrom        StringBuilder buf;
946320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        int insertionPoint = intString.length() - scale;
947320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        if (insertionPoint == 0) { /* Point goes right before intVal */
948320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            return "0." + intString;
949f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        }
950320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        else if (insertionPoint > 0) { /* Point goes inside intVal */
9517f0c06f737b6f1f6b3a5bb30111f95dd0ca586a2Brian Carlstrom            buf = new StringBuilder(intString);
952320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.insert(insertionPoint, '.');
953f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes        }
954320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        else { /* We must insert zeros between point and intVal */
9557f0c06f737b6f1f6b3a5bb30111f95dd0ca586a2Brian Carlstrom            buf = new StringBuilder(3 - insertionPoint + intString.length());
956320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append("0.");
957320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            for (int i = 0; i < -insertionPoint; i++) {
958320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson                buf.append('0');
959320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            }
960320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson            buf.append(intString);
961320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        }
962320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return buf.toString();
963320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
964320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
965320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson
966320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    /**
967320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>Calls the {@link Calendar#getTimeInMillis} method.
968320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * Prior to JDK1.4, this method was protected and therefore
969320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * cannot be invoked directly.</p>
970f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
971320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * <p>TODO: In future, this should be replaced by <code>cal.getTimeInMillis()</code>.</p>
972f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
973320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @param cal <code>Calendar</code> to get time in milliseconds.
974f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes     *
975320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     * @return Milliseconds of <code>cal</code>.
976320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson     */
977320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    private static long getCalendarTimeInMillis(final Calendar cal) {
978320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson        return cal.getTime().getTime();
979320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson    }
980320c9890e8241fb0ad05de6fa5e6c3eb3aece159Jesse Wilson}
981