001    /*
002     *  Copyright 2001-2011 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time.base;
017    
018    import java.io.Serializable;
019    
020    import org.joda.time.Chronology;
021    import org.joda.time.DateTimeUtils;
022    import org.joda.time.Interval;
023    import org.joda.time.Period;
024    import org.joda.time.PeriodType;
025    import org.joda.time.ReadableDuration;
026    import org.joda.time.ReadableInstant;
027    import org.joda.time.convert.ConverterManager;
028    import org.joda.time.convert.DurationConverter;
029    import org.joda.time.field.FieldUtils;
030    
031    /**
032     * BaseDuration is an abstract implementation of ReadableDuration that stores
033     * data in a <code>long</code> duration milliseconds field.
034     * <p>
035     * This class should generally not be used directly by API users.
036     * The {@link ReadableDuration} interface should be used when different 
037     * kinds of duration objects are to be referenced.
038     * <p>
039     * BaseDuration subclasses may be mutable and not thread-safe.
040     *
041     * @author Brian S O'Neill
042     * @author Stephen Colebourne
043     * @since 1.0
044     */
045    public abstract class BaseDuration
046            extends AbstractDuration
047            implements ReadableDuration, Serializable {
048    
049        /** Serialization version */
050        private static final long serialVersionUID = 2581698638990L;
051    
052        /** The duration length */
053        private volatile long iMillis;
054    
055        /**
056         * Creates a duration from the given millisecond duration.
057         *
058         * @param duration  the duration, in milliseconds
059         */
060        protected BaseDuration(long duration) {
061            super();
062            iMillis = duration;
063        }
064    
065        /**
066         * Creates a duration from the given interval endpoints.
067         *
068         * @param startInstant  interval start, in milliseconds
069         * @param endInstant  interval end, in milliseconds
070         * @throws ArithmeticException if the duration exceeds a 64 bit long
071         */
072        protected BaseDuration(long startInstant, long endInstant) {
073            super();
074            iMillis = FieldUtils.safeAdd(endInstant, -startInstant);
075        }
076    
077        /**
078         * Creates a duration from the given interval endpoints.
079         *
080         * @param start  interval start, null means now
081         * @param end  interval end, null means now
082         * @throws ArithmeticException if the duration exceeds a 64 bit long
083         */
084        protected BaseDuration(ReadableInstant start, ReadableInstant end) {
085            super();
086            if (start == end) {
087                iMillis = 0L;
088            } else {
089                long startMillis = DateTimeUtils.getInstantMillis(start);
090                long endMillis = DateTimeUtils.getInstantMillis(end);
091                iMillis = FieldUtils.safeAdd(endMillis, -startMillis);
092            }
093        }
094    
095        /**
096         * Creates a duration from the specified object using the
097         * {@link org.joda.time.convert.ConverterManager ConverterManager}.
098         *
099         * @param duration  duration to convert
100         * @throws IllegalArgumentException if duration is invalid
101         */
102        protected BaseDuration(Object duration) {
103            super();
104            DurationConverter converter = ConverterManager.getInstance().getDurationConverter(duration);
105            iMillis = converter.getDurationMillis(duration);
106        }
107    
108        //-----------------------------------------------------------------------
109        /**
110         * Gets the length of this duration in milliseconds.
111         *
112         * @return the length of the duration in milliseconds.
113         */
114        public long getMillis() {
115            return iMillis;
116        }
117    
118        //-----------------------------------------------------------------------
119        /**
120         * Sets the length of this duration in milliseconds.
121         * 
122         * @param duration  the new length of the duration
123         */
124        protected void setMillis(long duration) {
125            iMillis = duration;
126        }
127    
128        //-----------------------------------------------------------------------
129        /**
130         * Converts this duration to a Period instance using the specified period type
131         * and the ISO chronology.
132         * <p>
133         * Only precise fields in the period type will be used.
134         * At most these are hours, minutes, seconds and millis - the period
135         * type may restrict the selection further.
136         * <p>
137         * For more control over the conversion process, you must pair the duration with
138         * an instant, see {@link #toPeriodFrom(ReadableInstant, PeriodType)}.
139         * 
140         * @param type  the period type to use, null means standard
141         * @return a Period created using the millisecond duration from this instance
142         */
143        public Period toPeriod(PeriodType type) {
144            return new Period(getMillis(), type);
145        }
146    
147        /**
148         * Converts this duration to a Period instance using the standard period type
149         * and the specified chronology.
150         * <p>
151         * Only precise fields in the period type will be used.
152         * Exactly which fields are precise depends on the chronology.
153         * Only the time fields are precise for ISO chronology with a time zone.
154         * However, ISO UTC also has precise days and weeks.
155         * <p>
156         * For more control over the conversion process, you must pair the duration with
157         * an instant, see {@link #toPeriodFrom(ReadableInstant)} and
158         * {@link #toPeriodTo(ReadableInstant)}
159         * 
160         * @param chrono  the chronology to use, null means ISO default
161         * @return a Period created using the millisecond duration from this instance
162         */
163        public Period toPeriod(Chronology chrono) {
164            return new Period(getMillis(), chrono);
165        }
166    
167        /**
168         * Converts this duration to a Period instance using the specified period type
169         * and chronology.
170         * <p>
171         * Only precise fields in the period type will be used.
172         * Exactly which fields are precise depends on the chronology.
173         * Only the time fields are precise for ISO chronology with a time zone.
174         * However, ISO UTC also has precise days and weeks.
175         * <p>
176         * For more control over the conversion process, you must pair the duration with
177         * an instant, see {@link #toPeriodFrom(ReadableInstant, PeriodType)} and
178         * {@link #toPeriodTo(ReadableInstant, PeriodType)}
179         * 
180         * @param type  the period type to use, null means standard
181         * @param chrono  the chronology to use, null means ISO default
182         * @return a Period created using the millisecond duration from this instance
183         */
184        public Period toPeriod(PeriodType type, Chronology chrono) {
185            return new Period(getMillis(), type, chrono);
186        }
187    
188        /**
189         * Converts this duration to a Period instance by adding the duration to a start
190         * instant to obtain an interval using the standard period type.
191         * <p>
192         * This conversion will determine the fields of a period accurately.
193         * The results are based on the instant millis, the chronology of the instant,
194         * the standard period type and the length of this duration.
195         * 
196         * @param startInstant  the instant to calculate the period from, null means now
197         * @return a Period created using the millisecond duration from this instance
198         */
199        public Period toPeriodFrom(ReadableInstant startInstant) {
200            return new Period(startInstant, this);
201        }
202    
203        /**
204         * Converts this duration to a Period instance by adding the duration to a start
205         * instant to obtain an interval.
206         * <p>
207         * This conversion will determine the fields of a period accurately.
208         * The results are based on the instant millis, the chronology of the instant,
209         * the period type and the length of this duration.
210         * 
211         * @param startInstant  the instant to calculate the period from, null means now
212         * @param type  the period type determining how to split the duration into fields, null means All type
213         * @return a Period created using the millisecond duration from this instance
214         */
215        public Period toPeriodFrom(ReadableInstant startInstant, PeriodType type) {
216            return new Period(startInstant, this, type);
217        }
218    
219        /**
220         * Converts this duration to a Period instance by subtracting the duration
221         * from an end instant to obtain an interval using the standard period
222         * type.
223         * <p>
224         * This conversion will determine the fields of a period accurately.
225         * The results are based on the instant millis, the chronology of the instant,
226         * the standard period type and the length of this duration.
227         * 
228         * @param endInstant  the instant to calculate the period to, null means now
229         * @return a Period created using the millisecond duration from this instance
230         */
231        public Period toPeriodTo(ReadableInstant endInstant) {
232            return new Period(this, endInstant);
233        }
234    
235        /**
236         * Converts this duration to a Period instance by subtracting the duration
237         * from an end instant to obtain an interval using the standard period
238         * type.
239         * <p>
240         * This conversion will determine the fields of a period accurately.
241         * The results are based on the instant millis, the chronology of the instant,
242         * the period type and the length of this duration.
243         * 
244         * @param endInstant  the instant to calculate the period to, null means now
245         * @param type  the period type determining how to split the duration into fields, null means All type
246         * @return a Period created using the millisecond duration from this instance
247         */
248        public Period toPeriodTo(ReadableInstant endInstant, PeriodType type) {
249            return new Period(this, endInstant, type);
250        }
251    
252        /**
253         * Converts this duration to an Interval starting at the specified instant.
254         * 
255         * @param startInstant  the instant to start the interval at, null means now
256         * @return an Interval starting at the specified instant
257         */
258        public Interval toIntervalFrom(ReadableInstant startInstant) {
259            return new Interval(startInstant, this);
260        }
261    
262        /**
263         * Converts this duration to an Interval ending at the specified instant.
264         * 
265         * @param endInstant  the instant to end the interval at, null means now
266         * @return an Interval ending at the specified instant
267         */
268        public Interval toIntervalTo(ReadableInstant endInstant) {
269            return new Interval(this, endInstant);
270        }
271    
272    }