Source Code Cross Referenced for Duration.java in  » 6.0-JDK-Core » xml » javax » xml » datatype » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Home
Java Source Code / Java Documentation
1.6.0 JDK Core
2.6.0 JDK Modules
3.6.0 JDK Modules com.sun
4.6.0 JDK Modules com.sun.java
5.6.0 JDK Modules sun
6.6.0 JDK Platform
7.Ajax
8.Apache Harmony Java SE
9.Aspect oriented
10.Authentication Authorization
11.Blogger System
12.Build
13.Byte Code
14.Cache
15.Chart
16.Chat
17.Code Analyzer
18.Collaboration
19.Content Management System
20.Database Client
21.Database DBMS
22.Database JDBC Connection Pool
23.Database ORM
24.Development
25.EJB Server
26.ERP CRM Financial
27.ESB
28.Forum
29.Game
30.GIS
31.Graphic 3D
32.Graphic Library
33.Groupware
34.HTML Parser
35.IDE
36.IDE Eclipse
37.IDE Netbeans
38.Installer
39.Internationalization Localization
40.Inversion of Control
41.Issue Tracking
42.J2EE
43.J2ME
44.JBoss
45.JMS
46.JMX
47.Library
48.Mail Clients
49.Music
50.Net
51.Parser
52.PDF
53.Portal
54.Profiler
55.Project Management
56.Report
57.RSS RDF
58.Rule Engine
59.Science
60.Scripting
61.Search Engine
62.Security
63.Sevlet Container
64.Source Control
65.Swing Library
66.Template Engine
67.Test Coverage
68.Testing
69.UML
70.Web Crawler
71.Web Framework
72.Web Mail
73.Web Server
74.Web Services
75.Web Services apache cxf 2.2.6
76.Web Services AXIS2
77.Wiki Engine
78.Workflow Engines
79.XML
80.XML UI
Java Source Code / Java Documentation » 6.0 JDK Core » xml » javax.xml.datatype 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001        /*
002         * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
003         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004         *
005         * This code is free software; you can redistribute it and/or modify it
006         * under the terms of the GNU General Public License version 2 only, as
007         * published by the Free Software Foundation.  Sun designates this
008         * particular file as subject to the "Classpath" exception as provided
009         * by Sun in the LICENSE file that accompanied this code.
010         *
011         * This code is distributed in the hope that it will be useful, but WITHOUT
012         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013         * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014         * version 2 for more details (a copy is included in the LICENSE file that
015         * accompanied this code).
016         *
017         * You should have received a copy of the GNU General Public License version
018         * 2 along with this work; if not, write to the Free Software Foundation,
019         * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020         *
021         * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022         * CA 95054 USA or visit www.sun.com if you need additional information or
023         * have any questions.
024         */
025
026        package javax.xml.datatype;
027
028        import java.math.BigDecimal;
029        import java.math.BigInteger;
030        import java.util.Calendar;
031        import java.util.Date;
032        import java.util.GregorianCalendar;
033
034        import javax.xml.namespace.QName;
035
036        /**
037         * <p>Immutable representation of a time span as defined in
038         * the W3C XML Schema 1.0 specification.</p>
039         *
040         * <p>A Duration object represents a period of Gregorian time,
041         * which consists of six fields (years, months, days, hours,
042         * minutes, and seconds) plus a sign (+/-) field.</p>
043         *
044         * <p>The first five fields have non-negative (>=0) integers or null
045         * (which represents that the field is not set),
046         * and the seconds field has a non-negative decimal or null.
047         * A negative sign indicates a negative duration.</p>
048         *
049         * <p>This class provides a number of methods that make it easy
050         * to use for the duration datatype of XML Schema 1.0 with
051         * the errata.</p>
052         *
053         * <h2>Order relationship</h2>
054         * <p>Duration objects only have partial order, where two values A and B
055         * maybe either:</p>
056         * <ol>
057         *  <li>A&lt;B (A is shorter than B)
058         *  <li>A&gt;B (A is longer than B)
059         *  <li>A==B   (A and B are of the same duration)
060         *  <li>A&lt;>B (Comparison between A and B is indeterminate)
061         * </ol>
062         *
063         * <p>For example, 30 days cannot be meaningfully compared to one month.
064         * The {@link #compare(Duration duration)} method implements this
065         * relationship.</p>
066         *
067         * <p>See the {@link #isLongerThan(Duration)} method for details about
068         * the order relationship among <code>Duration</code> objects.</p>
069         *
070         * <h2>Operations over Duration</h2>
071         * <p>This class provides a set of basic arithmetic operations, such
072         * as addition, subtraction and multiplication.
073         * Because durations don't have total order, an operation could
074         * fail for some combinations of operations. For example, you cannot
075         * subtract 15 days from 1 month. See the javadoc of those methods
076         * for detailed conditions where this could happen.</p>
077         *
078         * <p>Also, division of a duration by a number is not provided because
079         * the <code>Duration</code> class can only deal with finite precision
080         * decimal numbers. For example, one cannot represent 1 sec divided by 3.</p>
081         *
082         * <p>However, you could substitute a division by 3 with multiplying
083         * by numbers such as 0.3 or 0.333.</p>
084         *
085         * <h2>Range of allowed values</h2>
086         * <p>
087         * Because some operations of <code>Duration</code> rely on {@link Calendar}
088         * even though {@link Duration} can hold very large or very small values,
089         * some of the methods may not work correctly on such <code>Duration</code>s.
090         * The impacted methods document their dependency on {@link Calendar}.
091         *
092         * @author <a href="mailto:Joseph.Fialli@Sun.COM">Joseph Fialli</a>
093         * @author <a href="mailto:Kohsuke.Kawaguchi@Sun.com">Kohsuke Kawaguchi</a>
094         * @author <a href="mailto:Jeff.Suttor@Sun.com">Jeff Suttor</a>
095         * @author <a href="mailto:Sunitha.Reddy@Sun.com">Sunitha Reddy</a>
096         * @version $Revision: 1.7 $, $Date: 2006/01/12 18:49:19 $
097         * @see XMLGregorianCalendar#add(Duration)
098         * @since 1.5
099         */
100        public abstract class Duration {
101
102            /**
103             * <p>Debugging <code>true</code> or <code>false</code>.</p>
104             */
105            private static final boolean DEBUG = true;
106
107            /**
108             * Default no-arg constructor.
109             *
110             * <p>Note: Always use the {@link DatatypeFactory} to
111             * construct an instance of <code>Duration</code>.
112             * The constructor on this class cannot be guaranteed to
113             * produce an object with a consistent state and may be
114             * removed in the future.</p>
115             */
116            public Duration() {
117            }
118
119            /**
120             * <p>Return the name of the XML Schema date/time type that this instance
121             * maps to. Type is computed based on fields that are set,
122             * i.e. {@link #isSet(DatatypeConstants.Field field)} == <code>true</code>.</p>
123             *
124             * <table border="2" rules="all" cellpadding="2">
125             *   <thead>
126             *     <tr>
127             *       <th align="center" colspan="7">
128             *         Required fields for XML Schema 1.0 Date/Time Datatypes.<br/>
129             *         <i>(timezone is optional for all date/time datatypes)</i>
130             *       </th>
131             *     </tr>
132             *   </thead>
133             *   <tbody>
134             *     <tr>
135             *       <td>Datatype</td>
136             *       <td>year</td>
137             *       <td>month</td>
138             *       <td>day</td>
139             *       <td>hour</td>
140             *       <td>minute</td>
141             *       <td>second</td>
142             *     </tr>
143             *     <tr>
144             *       <td>{@link DatatypeConstants#DURATION}</td>
145             *       <td>X</td>
146             *       <td>X</td>
147             *       <td>X</td>
148             *       <td>X</td>
149             *       <td>X</td>
150             *       <td>X</td>
151             *     </tr>
152             *     <tr>
153             *       <td>{@link DatatypeConstants#DURATION_DAYTIME}</td>
154             *       <td></td>
155             *       <td></td>
156             *       <td>X</td>
157             *       <td>X</td>
158             *       <td>X</td>
159             *       <td>X</td>
160             *     </tr>
161             *     <tr>
162             *       <td>{@link DatatypeConstants#DURATION_YEARMONTH}</td>
163             *       <td>X</td>
164             *       <td>X</td>
165             *       <td></td>
166             *       <td></td>
167             *       <td></td>
168             *       <td></td>
169             *     </tr>
170             *   </tbody>
171             * </table>
172             *
173             * @return one of the following constants:
174             *   {@link DatatypeConstants#DURATION},
175             *   {@link DatatypeConstants#DURATION_DAYTIME} or
176             *   {@link DatatypeConstants#DURATION_YEARMONTH}.
177             *
178             * @throws IllegalStateException If the combination of set fields does not match one of the XML Schema date/time datatypes.
179             */
180            public QName getXMLSchemaType() {
181
182                boolean yearSet = isSet(DatatypeConstants.YEARS);
183                boolean monthSet = isSet(DatatypeConstants.MONTHS);
184                boolean daySet = isSet(DatatypeConstants.DAYS);
185                boolean hourSet = isSet(DatatypeConstants.HOURS);
186                boolean minuteSet = isSet(DatatypeConstants.MINUTES);
187                boolean secondSet = isSet(DatatypeConstants.SECONDS);
188
189                // DURATION
190                if (yearSet && monthSet && daySet && hourSet && minuteSet
191                        && secondSet) {
192                    return DatatypeConstants.DURATION;
193                }
194
195                // DURATION_DAYTIME
196                if (!yearSet && !monthSet && daySet && hourSet && minuteSet
197                        && secondSet) {
198                    return DatatypeConstants.DURATION_DAYTIME;
199                }
200
201                // DURATION_YEARMONTH
202                if (yearSet && monthSet && !daySet && !hourSet && !minuteSet
203                        && !secondSet) {
204                    return DatatypeConstants.DURATION_YEARMONTH;
205                }
206
207                // nothing matches
208                throw new IllegalStateException(
209                        "javax.xml.datatype.Duration#getXMLSchemaType():"
210                                + " this Duration does not match one of the XML Schema date/time datatypes:"
211                                + " year set = " + yearSet + " month set = "
212                                + monthSet + " day set = " + daySet
213                                + " hour set = " + hourSet + " minute set = "
214                                + minuteSet + " second set = " + secondSet);
215            }
216
217            /**
218             * Returns the sign of this duration in -1,0, or 1.
219             *
220             * @return
221             *      -1 if this duration is negative, 0 if the duration is zero,
222             *      and 1 if the duration is positive.
223             */
224            public abstract int getSign();
225
226            /**
227             * <p>Get the years value of this <code>Duration</code> as an <code>int</code> or <code>0</code> if not present.</p>
228             *
229             * <p><code>getYears()</code> is a convenience method for
230             * {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)}.</p>
231             *
232             * <p>As the return value is an <code>int</code>, an incorrect value will be returned for <code>Duration</code>s
233             * with years that go beyond the range of an <code>int</code>.
234             * Use {@link #getField(DatatypeConstants.Field field) getField(DatatypeConstants.YEARS)} to avoid possible loss of precision.</p>
235             *
236             * @return If the years field is present, return its value as an <code>int</code>, else return <code>0</code>.
237             */
238            public int getYears() {
239                return getField(DatatypeConstants.YEARS).intValue();
240            }
241
242            /**
243             * Obtains the value of the MONTHS field as an integer value,
244             * or 0 if not present.
245             *
246             * This method works just like {@link #getYears()} except
247             * that this method works on the MONTHS field.
248             *
249             * @return Months of this <code>Duration</code>.
250             */
251            public int getMonths() {
252                return getField(DatatypeConstants.MONTHS).intValue();
253            }
254
255            /**
256             * Obtains the value of the DAYS field as an integer value,
257             * or 0 if not present.
258             *
259             * This method works just like {@link #getYears()} except
260             * that this method works on the DAYS field.
261             *
262             * @return Days of this <code>Duration</code>.
263             */
264            public int getDays() {
265                return getField(DatatypeConstants.DAYS).intValue();
266            }
267
268            /**
269             * Obtains the value of the HOURS field as an integer value,
270             * or 0 if not present.
271             *
272             * This method works just like {@link #getYears()} except
273             * that this method works on the HOURS field.
274             *
275             * @return Hours of this <code>Duration</code>.
276             *
277             */
278            public int getHours() {
279                return getField(DatatypeConstants.HOURS).intValue();
280            }
281
282            /**
283             * Obtains the value of the MINUTES field as an integer value,
284             * or 0 if not present.
285             *
286             * This method works just like {@link #getYears()} except
287             * that this method works on the MINUTES field.
288             *
289             * @return Minutes of this <code>Duration</code>.
290             *
291             */
292            public int getMinutes() {
293                return getField(DatatypeConstants.MINUTES).intValue();
294            }
295
296            /**
297             * Obtains the value of the SECONDS field as an integer value,
298             * or 0 if not present.
299             *
300             * This method works just like {@link #getYears()} except
301             * that this method works on the SECONDS field.
302             *
303             * @return seconds in the integer value. The fraction of seconds
304             *   will be discarded (for example, if the actual value is 2.5,
305             *   this method returns 2)
306             */
307            public int getSeconds() {
308                return getField(DatatypeConstants.SECONDS).intValue();
309            }
310
311            /**
312             * <p>Returns the length of the duration in milli-seconds.</p>
313             *
314             * <p>If the seconds field carries more digits than milli-second order,
315             * those will be simply discarded (or in other words, rounded to zero.)
316             * For example, for any Calendar value <code>x</code>,</p>
317             * <pre>
318             * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
319             * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
320             * </pre>
321             *
322             * <p>
323             * Note that this method uses the {@link #addTo(Calendar)} method,
324             * which may work incorrectly with <code>Duration</code> objects with
325             * very large values in its fields. See the {@link #addTo(Calendar)}
326             * method for details.
327             *
328             * @param startInstant
329             *      The length of a month/year varies. The <code>startInstant</code> is
330             *      used to disambiguate this variance. Specifically, this method
331             *      returns the difference between <code>startInstant</code> and
332             *      <code>startInstant+duration</code>
333             *
334             * @return milliseconds between <code>startInstant</code> and
335             *   <code>startInstant</code> plus this <code>Duration</code>
336             *
337             * @throws NullPointerException if <code>startInstant</code> parameter
338             * is null.
339             *
340             */
341            public long getTimeInMillis(final Calendar startInstant) {
342                Calendar cal = (Calendar) startInstant.clone();
343                addTo(cal);
344                return getCalendarTimeInMillis(cal)
345                        - getCalendarTimeInMillis(startInstant);
346            }
347
348            /**
349             * <p>Returns the length of the duration in milli-seconds.</p>
350             *
351             * <p>If the seconds field carries more digits than milli-second order,
352             * those will be simply discarded (or in other words, rounded to zero.)
353             * For example, for any <code>Date</code> value <code>x</code>,</p>
354             * <pre>
355             * <code>new Duration("PT10.00099S").getTimeInMills(x) == 10000</code>.
356             * <code>new Duration("-PT10.00099S").getTimeInMills(x) == -10000</code>.
357             * </pre>
358             *
359             * <p>
360             * Note that this method uses the {@link #addTo(Date)} method,
361             * which may work incorrectly with <code>Duration</code> objects with
362             * very large values in its fields. See the {@link #addTo(Date)}
363             * method for details.
364             *
365             * @param startInstant
366             *      The length of a month/year varies. The <code>startInstant</code> is
367             *      used to disambiguate this variance. Specifically, this method
368             *      returns the difference between <code>startInstant</code> and
369             *      <code>startInstant+duration</code>.
370             *
371             * @throws NullPointerException
372             *      If the startInstant parameter is null.
373             *
374             * @return milliseconds between <code>startInstant</code> and
375             *   <code>startInstant</code> plus this <code>Duration</code>
376             *
377             * @see #getTimeInMillis(Calendar)
378             */
379            public long getTimeInMillis(final Date startInstant) {
380                Calendar cal = new GregorianCalendar();
381                cal.setTime(startInstant);
382                this .addTo(cal);
383                return getCalendarTimeInMillis(cal) - startInstant.getTime();
384            }
385
386            /**
387             * Gets the value of a field.
388             *
389             * Fields of a duration object may contain arbitrary large value.
390             * Therefore this method is designed to return a {@link Number} object.
391             *
392             * In case of YEARS, MONTHS, DAYS, HOURS, and MINUTES, the returned
393             * number will be a non-negative integer. In case of seconds,
394             * the returned number may be a non-negative decimal value.
395             *
396             * @param field
397             *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
398             *      MINUTES, or SECONDS.)
399             * @return
400             *      If the specified field is present, this method returns
401             *      a non-null non-negative {@link Number} object that
402             *      represents its value. If it is not present, return null.
403             *      For YEARS, MONTHS, DAYS, HOURS, and MINUTES, this method
404             *      returns a {@link java.math.BigInteger} object. For SECONDS, this
405             *      method returns a {@link java.math.BigDecimal}.
406             *
407             * @throws NullPointerException If the <code>field</code> is <code>null</code>.
408             */
409            public abstract Number getField(final DatatypeConstants.Field field);
410
411            /**
412             * Checks if a field is set.
413             *
414             * A field of a duration object may or may not be present.
415             * This method can be used to test if a field is present.
416             *
417             * @param field
418             *      one of the six Field constants (YEARS,MONTHS,DAYS,HOURS,
419             *      MINUTES, or SECONDS.)
420             * @return
421             *      true if the field is present. false if not.
422             *
423             * @throws NullPointerException
424             *      If the field parameter is null.
425             */
426            public abstract boolean isSet(final DatatypeConstants.Field field);
427
428            /**
429             * <p>Computes a new duration whose value is <code>this+rhs</code>.</p>
430             *
431             * <p>For example,</p>
432             * <pre>
433             * "1 day" + "-3 days" = "-2 days"
434             * "1 year" + "1 day" = "1 year and 1 day"
435             * "-(1 hour,50 minutes)" + "-20 minutes" = "-(1 hours,70 minutes)"
436             * "15 hours" + "-3 days" = "-(2 days,9 hours)"
437             * "1 year" + "-1 day" = IllegalStateException
438             * </pre>
439             *
440             * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
441             * there are cases where the operation fails in
442             * {@link IllegalStateException}.</p>
443             *
444             * <p>
445             * Formally, the computation is defined as follows.</p>
446             * <p>
447             * Firstly, we can assume that two <code>Duration</code>s to be added
448             * are both positive without losing generality (i.e.,
449             * <code>(-X)+Y=Y-X</code>, <code>X+(-Y)=X-Y</code>,
450             * <code>(-X)+(-Y)=-(X+Y)</code>)
451             *
452             * <p>
453             * Addition of two positive <code>Duration</code>s are simply defined as
454             * field by field addition where missing fields are treated as 0.
455             * <p>
456             * A field of the resulting <code>Duration</code> will be unset if and
457             * only if respective fields of two input <code>Duration</code>s are unset.
458             * <p>
459             * Note that <code>lhs.add(rhs)</code> will be always successful if
460             * <code>lhs.signum()*rhs.signum()!=-1</code> or both of them are
461             * normalized.</p>
462             *
463             * @param rhs <code>Duration</code> to add to this <code>Duration</code>
464             *
465             * @return
466             *      non-null valid Duration object.
467             *
468             * @throws NullPointerException
469             *      If the rhs parameter is null.
470             * @throws IllegalStateException
471             *      If two durations cannot be meaningfully added. For
472             *      example, adding negative one day to one month causes
473             *      this exception.
474             *
475             *
476             * @see #subtract(Duration)
477             */
478            public abstract Duration add(final Duration rhs);
479
480            /**
481             * Adds this duration to a {@link Calendar} object.
482             *
483             * <p>
484             * Calls {@link java.util.Calendar#add(int,int)} in the
485             * order of YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS, and MILLISECONDS
486             * if those fields are present. Because the {@link Calendar} class
487             * uses int to hold values, there are cases where this method
488             * won't work correctly (for example if values of fields
489             * exceed the range of int.)
490             * </p>
491             *
492             * <p>
493             * Also, since this duration class is a Gregorian duration, this
494             * method will not work correctly if the given {@link Calendar}
495             * object is based on some other calendar systems.
496             * </p>
497             *
498             * <p>
499             * Any fractional parts of this <code>Duration</code> object
500             * beyond milliseconds will be simply ignored. For example, if
501             * this duration is "P1.23456S", then 1 is added to SECONDS,
502             * 234 is added to MILLISECONDS, and the rest will be unused.
503             * </p>
504             *
505             * <p>
506             * Note that because {@link Calendar#add(int, int)} is using
507             * <code>int</code>, <code>Duration</code> with values beyond the
508             * range of <code>int</code> in its fields
509             * will cause overflow/underflow to the given {@link Calendar}.
510             * {@link XMLGregorianCalendar#add(Duration)} provides the same
511             * basic operation as this method while avoiding
512             * the overflow/underflow issues.
513             *
514             * @param calendar
515             *      A calendar object whose value will be modified.
516             * @throws NullPointerException
517             *      if the calendar parameter is null.
518             */
519            public abstract void addTo(Calendar calendar);
520
521            /**
522             * Adds this duration to a {@link Date} object.
523             *
524             * <p>
525             * The given date is first converted into
526             * a {@link java.util.GregorianCalendar}, then the duration
527             * is added exactly like the {@link #addTo(Calendar)} method.
528             *
529             * <p>
530             * The updated time instant is then converted back into a
531             * {@link Date} object and used to update the given {@link Date} object.
532             *
533             * <p>
534             * This somewhat redundant computation is necessary to unambiguously
535             * determine the duration of months and years.
536             *
537             * @param date
538             *      A date object whose value will be modified.
539             * @throws NullPointerException
540             *      if the date parameter is null.
541             */
542            public void addTo(Date date) {
543
544                // check data parameter
545                if (date == null) {
546                    throw new NullPointerException("Cannot call "
547                            + this .getClass().getName()
548                            + "#addTo(Date date) with date == null.");
549                }
550
551                Calendar cal = new GregorianCalendar();
552                cal.setTime(date);
553                this .addTo(cal);
554                date.setTime(getCalendarTimeInMillis(cal));
555            }
556
557            /**
558             * <p>Computes a new duration whose value is <code>this-rhs</code>.</p>
559             *
560             * <p>For example:</p>
561             * <pre>
562             * "1 day" - "-3 days" = "4 days"
563             * "1 year" - "1 day" = IllegalStateException
564             * "-(1 hour,50 minutes)" - "-20 minutes" = "-(1hours,30 minutes)"
565             * "15 hours" - "-3 days" = "3 days and 15 hours"
566             * "1 year" - "-1 day" = "1 year and 1 day"
567             * </pre>
568             *
569             * <p>Since there's no way to meaningfully subtract 1 day from 1 month,
570             * there are cases where the operation fails in {@link IllegalStateException}.</p>
571             *
572             * <p>Formally the computation is defined as follows.
573             * First, we can assume that two <code>Duration</code>s are both positive
574             * without losing generality.  (i.e.,
575             * <code>(-X)-Y=-(X+Y)</code>, <code>X-(-Y)=X+Y</code>,
576             * <code>(-X)-(-Y)=-(X-Y)</code>)</p>
577             *
578             * <p>Then two durations are subtracted field by field.
579             * If the sign of any non-zero field <code>F</code> is different from
580             * the sign of the most significant field,
581             * 1 (if <code>F</code> is negative) or -1 (otherwise)
582             * will be borrowed from the next bigger unit of <code>F</code>.</p>
583             *
584             * <p>This process is repeated until all the non-zero fields have
585             * the same sign.</p>
586             *
587             * <p>If a borrow occurs in the days field (in other words, if
588             * the computation needs to borrow 1 or -1 month to compensate
589             * days), then the computation fails by throwing an
590             * {@link IllegalStateException}.</p>
591             *
592             * @param rhs <code>Duration</code> to subtract from this <code>Duration</code>.
593             *
594             * @return New <code>Duration</code> created from subtracting <code>rhs</code> from this <code>Duration</code>.
595             *
596             * @throws IllegalStateException
597             *      If two durations cannot be meaningfully subtracted. For
598             *      example, subtracting one day from one month causes
599             *      this exception.
600             *
601             * @throws NullPointerException
602             *      If the rhs parameter is null.
603             *
604             * @see #add(Duration)
605             */
606            public Duration subtract(final Duration rhs) {
607                return add(rhs.negate());
608            }
609
610            /**
611             * <p>Computes a new duration whose value is <code>factor</code> times
612             * longer than the value of this duration.</p>
613             *
614             * <p>This method is provided for the convenience.
615             * It is functionally equivalent to the following code:</p>
616             * <pre>
617             * multiply(new BigDecimal(String.valueOf(factor)))
618             * </pre>
619             *
620             * @param factor Factor times longer of new <code>Duration</code> to create.
621             *
622             * @return New <code>Duration</code> that is <code>factor</code>times longer than this <code>Duration</code>.
623             *
624             * @see #multiply(BigDecimal)
625             */
626            public Duration multiply(int factor) {
627                return multiply(new BigDecimal(String.valueOf(factor)));
628            }
629
630            /**
631             * Computes a new duration whose value is <code>factor</code> times
632             * longer than the value of this duration.
633             *
634             * <p>
635             * For example,
636             * <pre>
637             * "P1M" (1 month) * "12" = "P12M" (12 months)
638             * "PT1M" (1 min) * "0.3" = "PT18S" (18 seconds)
639             * "P1M" (1 month) * "1.5" = IllegalStateException
640             * </pre>
641             *
642             * <p>
643             * Since the <code>Duration</code> class is immutable, this method
644             * doesn't change the value of this object. It simply computes
645             * a new Duration object and returns it.
646             *
647             * <p>
648             * The operation will be performed field by field with the precision
649             * of {@link BigDecimal}. Since all the fields except seconds are
650             * restricted to hold integers,
651             * any fraction produced by the computation will be
652             * carried down toward the next lower unit. For example,
653             * if you multiply "P1D" (1 day) with "0.5", then it will be 0.5 day,
654             * which will be carried down to "PT12H" (12 hours).
655             * When fractions of month cannot be meaningfully carried down
656             * to days, or year to months, this will cause an
657             * {@link IllegalStateException} to be thrown.
658             * For example if you multiple one month by 0.5.</p>
659             *
660             * <p>
661             * To avoid {@link IllegalStateException}, use
662             * the {@link #normalizeWith(Calendar)} method to remove the years
663             * and months fields.
664             *
665             * @param factor to multiply by
666             *
667             * @return
668             *      returns a non-null valid <code>Duration</code> object
669             *
670             * @throws IllegalStateException if operation produces fraction in
671             * the months field.
672             *
673             * @throws NullPointerException if the <code>factor</code> parameter is
674             * <code>null</code>.
675             *
676             */
677            public abstract Duration multiply(final BigDecimal factor);
678
679            /**
680             * Returns a new <code>Duration</code> object whose
681             * value is <code>-this</code>.
682             *
683             * <p>
684             * Since the <code>Duration</code> class is immutable, this method
685             * doesn't change the value of this object. It simply computes
686             * a new Duration object and returns it.
687             *
688             * @return
689             *      always return a non-null valid <code>Duration</code> object.
690             */
691            public abstract Duration negate();
692
693            /**
694             * <p>Converts the years and months fields into the days field
695             * by using a specific time instant as the reference point.</p>
696             *
697             * <p>For example, duration of one month normalizes to 31 days
698             * given the start time instance "July 8th 2003, 17:40:32".</p>
699             *
700             * <p>Formally, the computation is done as follows:</p>
701             * <ol>
702             *  <li>the given Calendar object is cloned</li>
703             *  <li>the years, months and days fields will be added to the {@link Calendar} object
704             *      by using the {@link Calendar#add(int,int)} method</li>
705             *  <li>the difference between the two Calendars in computed in milliseconds and converted to days,
706             *     if a remainder occurs due to Daylight Savings Time, it is discarded</li>
707             *  <li>the computed days, along with the hours, minutes and seconds
708             *      fields of this duration object is used to construct a new
709             *      Duration object.</li>
710             * </ol>
711             *
712             * <p>Note that since the Calendar class uses <code>int</code> to
713             * hold the value of year and month, this method may produce
714             * an unexpected result if this duration object holds
715             * a very large value in the years or months fields.</p>
716             *
717             * @param startTimeInstant <code>Calendar</code> reference point.
718             *
719             * @return <code>Duration</code> of years and months of this <code>Duration</code> as days.
720             *
721             * @throws NullPointerException If the startTimeInstant parameter is null.
722             */
723            public abstract Duration normalizeWith(
724                    final Calendar startTimeInstant);
725
726            /**
727             * <p>Partial order relation comparison with this <code>Duration</code> instance.</p>
728             *
729             * <p>Comparison result must be in accordance with
730             * <a href="http://www.w3.org/TR/xmlschema-2/#duration-order">W3C XML Schema 1.0 Part 2, Section 3.2.7.6.2,
731             * <i>Order relation on duration</i></a>.</p>
732             *
733             * <p>Return:</p>
734             * <ul>
735             *   <li>{@link DatatypeConstants#LESSER} if this <code>Duration</code> is shorter than <code>duration</code> parameter</li>
736             *   <li>{@link DatatypeConstants#EQUAL} if this <code>Duration</code> is equal to <code>duration</code> parameter</li>
737             *   <li>{@link DatatypeConstants#GREATER} if this <code>Duration</code> is longer than <code>duration</code> parameter</li>
738             *   <li>{@link DatatypeConstants#INDETERMINATE} if a conclusive partial order relation cannot be determined</li>
739             * </ul>
740             *
741             * @param duration to compare
742             *
743             * @return the relationship between <code>this</code> <code>Duration</code>and <code>duration</code> parameter as
744             *   {@link DatatypeConstants#LESSER}, {@link DatatypeConstants#EQUAL}, {@link DatatypeConstants#GREATER}
745             *   or {@link DatatypeConstants#INDETERMINATE}.
746             *
747             * @throws UnsupportedOperationException If the underlying implementation
748             *   cannot reasonably process the request, e.g. W3C XML Schema allows for
749             *   arbitrarily large/small/precise values, the request may be beyond the
750             *   implementations capability.
751             * @throws NullPointerException if <code>duration</code> is <code>null</code>.
752             *
753             * @see #isShorterThan(Duration)
754             * @see #isLongerThan(Duration)
755             */
756            public abstract int compare(final Duration duration);
757
758            /**
759             * <p>Checks if this duration object is strictly longer than
760             * another <code>Duration</code> object.</p>
761             *
762             * <p>Duration X is "longer" than Y if and only if X>Y
763             * as defined in the section 3.2.6.2 of the XML Schema 1.0
764             * specification.</p>
765             *
766             * <p>For example, "P1D" (one day) > "PT12H" (12 hours) and
767             * "P2Y" (two years) > "P23M" (23 months).</p>
768             *
769             * @param duration <code>Duration</code> to test this <code>Duration</code> against.
770             *
771             * @throws UnsupportedOperationException If the underlying implementation
772             *   cannot reasonably process the request, e.g. W3C XML Schema allows for
773             *   arbitrarily large/small/precise values, the request may be beyond the
774             *   implementations capability.
775             * @throws NullPointerException If <code>duration</code> is null.
776             *
777             * @return
778             *      true if the duration represented by this object
779             *      is longer than the given duration. false otherwise.
780             *
781             * @see #isShorterThan(Duration)
782             * @see #compare(Duration duration)
783             */
784            public boolean isLongerThan(final Duration duration) {
785                return compare(duration) == DatatypeConstants.GREATER;
786            }
787
788            /**
789             * <p>Checks if this duration object is strictly shorter than
790             * another <code>Duration</code> object.</p>
791             *
792             * @param duration <code>Duration</code> to test this <code>Duration</code> against.
793             *
794             * @return <code>true</code> if <code>duration</code> parameter is shorter than this <code>Duration</code>,
795             *   else <code>false</code>.
796             *
797             * @throws UnsupportedOperationException If the underlying implementation
798             *   cannot reasonably process the request, e.g. W3C XML Schema allows for
799             *   arbitrarily large/small/precise values, the request may be beyond the
800             *   implementations capability.
801             * @throws NullPointerException if <code>duration</code> is null.
802             *
803             * @see #isLongerThan(Duration duration)
804             * @see #compare(Duration duration)
805             */
806            public boolean isShorterThan(final Duration duration) {
807                return compare(duration) == DatatypeConstants.LESSER;
808            }
809
810            /**
811             * <p>Checks if this duration object has the same duration
812             * as another <code>Duration</code> object.</p>
813             *
814             * <p>For example, "P1D" (1 day) is equal to "PT24H" (24 hours).</p>
815             *
816             * <p>Duration X is equal to Y if and only if time instant
817             * t+X and t+Y are the same for all the test time instants
818             * specified in the section 3.2.6.2 of the XML Schema 1.0
819             * specification.</p>
820             *
821             * <p>Note that there are cases where two <code>Duration</code>s are
822             * "incomparable" to each other, like one month and 30 days.
823             * For example,</p>
824             * <pre>
825             * !new Duration("P1M").isShorterThan(new Duration("P30D"))
826             * !new Duration("P1M").isLongerThan(new Duration("P30D"))
827             * !new Duration("P1M").equals(new Duration("P30D"))
828             * </pre>
829             *
830             * @param duration
831             *      The object to compare this <code>Duration</code> against.
832             *
833             * @return
834             *      <code>true</code> if this duration is the same length as
835             *         <code>duration</code>.
836             *      <code>false</code> if <code>duration</code> is <code>null</code>,
837             *         is not a
838             *         <code>Duration</code> object,
839             *         or its length is different from this duration.
840             *
841             * @throws UnsupportedOperationException If the underlying implementation
842             *   cannot reasonably process the request, e.g. W3C XML Schema allows for
843             *   arbitrarily large/small/precise values, the request may be beyond the
844             *   implementations capability.
845             *
846             * @see #compare(Duration duration)
847             */
848            public boolean equals(final Object duration) {
849
850                if (duration == null || !(duration instanceof  Duration)) {
851                    return false;
852                }
853
854                return compare((Duration) duration) == DatatypeConstants.EQUAL;
855            }
856
857            /**
858             * Returns a hash code consistent with the definition of the equals method.
859             *
860             * @see Object#hashCode()
861             */
862            public abstract int hashCode();
863
864            /**
865             * <p>Returns a <code>String</code> representation of this <code>Duration</code> <code>Object</code>.</p>
866             *
867             * <p>The result is formatted according to the XML Schema 1.0 spec and can be always parsed back later into the
868             * equivalent <code>Duration</code> <code>Object</code> by {@link DatatypeFactory#newDuration(String  lexicalRepresentation)}.</p>
869             *
870             * <p>Formally, the following holds for any <code>Duration</code>
871             * <code>Object</code> x:</p>
872             * <pre>
873             * new Duration(x.toString()).equals(x)
874             * </pre>
875             *
876             * @return A non-<code>null</code> valid <code>String</code> representation of this <code>Duration</code>.
877             */
878            public String toString() {
879
880                StringBuffer buf = new StringBuffer();
881
882                if (getSign() < 0) {
883                    buf.append('-');
884                }
885                buf.append('P');
886
887                BigInteger years = (BigInteger) getField(DatatypeConstants.YEARS);
888                if (years != null) {
889                    buf.append(years + "Y");
890                }
891
892                BigInteger months = (BigInteger) getField(DatatypeConstants.MONTHS);
893                if (months != null) {
894                    buf.append(months + "M");
895                }
896
897                BigInteger days = (BigInteger) getField(DatatypeConstants.DAYS);
898                if (days != null) {
899                    buf.append(days + "D");
900                }
901
902                BigInteger hours = (BigInteger) getField(DatatypeConstants.HOURS);
903                BigInteger minutes = (BigInteger) getField(DatatypeConstants.MINUTES);
904                BigDecimal seconds = (BigDecimal) getField(DatatypeConstants.SECONDS);
905                if (hours != null || minutes != null || seconds != null) {
906                    buf.append('T');
907                    if (hours != null) {
908                        buf.append(hours + "H");
909                    }
910                    if (minutes != null) {
911                        buf.append(minutes + "M");
912                    }
913                    if (seconds != null) {
914                        buf.append(toString(seconds) + "S");
915                    }
916                }
917
918                return buf.toString();
919            }
920
921            /**
922             * <p>Turns {@link BigDecimal} to a string representation.</p>
923             *
924             * <p>Due to a behavior change in the {@link BigDecimal#toString()}
925             * method in JDK1.5, this had to be implemented here.</p>
926             *
927             * @param bd <code>BigDecimal</code> to format as a <code>String</code>
928             *
929             * @return  <code>String</code> representation of <code>BigDecimal</code>
930             */
931            private String toString(BigDecimal bd) {
932                String intString = bd.unscaledValue().toString();
933                int scale = bd.scale();
934
935                if (scale == 0) {
936                    return intString;
937                }
938
939                /* Insert decimal point */
940                StringBuffer buf;
941                int insertionPoint = intString.length() - scale;
942                if (insertionPoint == 0) { /* Point goes right before intVal */
943                    return "0." + intString;
944                } else if (insertionPoint > 0) { /* Point goes inside intVal */
945                    buf = new StringBuffer(intString);
946                    buf.insert(insertionPoint, '.');
947                } else { /* We must insert zeros between point and intVal */
948                    buf = new StringBuffer(3 - insertionPoint
949                            + intString.length());
950                    buf.append("0.");
951                    for (int i = 0; i < -insertionPoint; i++) {
952                        buf.append('0');
953                    }
954                    buf.append(intString);
955                }
956                return buf.toString();
957            }
958
959            /**
960             * <p>Calls the {@link Calendar#getTimeInMillis} method.
961             * Prior to JDK1.4, this method was protected and therefore
962             * cannot be invoked directly.</p>
963             *
964             * <p>TODO: In future, this should be replaced by <code>cal.getTimeInMillis()</code>.</p>
965             *
966             * @param cal <code>Calendar</code> to get time in milliseconds.
967             *
968             * @return Milliseconds of <code>cal</code>.
969             */
970            private static long getCalendarTimeInMillis(final Calendar cal) {
971                return cal.getTime().getTime();
972            }
973        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.