001    /*
002     *  Copyright 2001-2005 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;
017    
018    import java.io.Serializable;
019    
020    import org.joda.time.base.BaseInterval;
021    import org.joda.time.field.FieldUtils;
022    import org.joda.time.format.ISODateTimeFormat;
023    import org.joda.time.format.ISOPeriodFormat;
024    
025    /**
026     * MutableInterval is the standard implementation of a mutable time interval.
027     * <p>
028     * A time interval represents a period of time between two instants.
029     * Intervals are inclusive of the start instant and exclusive of the end.
030     * The end instant is always greater than or equal to the start instant.
031     * <p>
032     * Intervals have a fixed millisecond duration.
033     * This is the difference between the start and end instants.
034     * The duration is represented separately by {@link ReadableDuration}.
035     * As a result, intervals are not comparable.
036     * To compare the length of two intervals, you should compare their durations.
037     * <p>
038     * An interval can also be converted to a {@link ReadablePeriod}.
039     * This represents the difference between the start and end points in terms of fields
040     * such as years and days.
041     * <p>
042     * If performing significant calculations on an interval, it may be faster to
043     * convert an Interval object to a MutableInterval one.
044     * <p>
045     * MutableInterval is mutable and not thread-safe, unless concurrent threads
046     * are not invoking mutator methods.
047     *
048     * @author Stephen Colebourne
049     * @author Brian S O'Neill
050     * @since 1.0
051     */
052    public class MutableInterval
053            extends BaseInterval
054            implements ReadWritableInterval, Cloneable, Serializable {
055    
056        /** Serialization version */
057        private static final long serialVersionUID = -5982824024992428470L;
058    
059        //-----------------------------------------------------------------------
060        /**
061         * Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
062         */
063        public MutableInterval() {
064            super(0L, 0L, null);
065        }
066    
067        /**
068         * Constructs an interval from a start and end instant with the ISO default chronology.
069         * 
070         * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
071         * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
072         * @throws IllegalArgumentException if the end is before the start
073         */
074        public MutableInterval(long startInstant, long endInstant) {
075            super(startInstant, endInstant, null);
076        }
077    
078        /**
079         * Constructs an interval from a start and end instant with a chronology.
080         * 
081         * @param chronology  the chronology to use, null is ISO default
082         * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
083         * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
084         * @throws IllegalArgumentException if the end is before the start
085         */
086        public MutableInterval(long startInstant, long endInstant, Chronology chronology) {
087            super(startInstant, endInstant, chronology);
088        }
089    
090        /**
091         * Constructs an interval from a start and end instant.
092         * <p>
093         * The chronology used is that of the start instant.
094         * 
095         * @param start  start of this interval, null means now
096         * @param end  end of this interval, null means now
097         * @throws IllegalArgumentException if the end is before the start
098         */
099        public MutableInterval(ReadableInstant start, ReadableInstant end) {
100            super(start, end);
101        }
102    
103        /**
104         * Constructs an interval from a start instant and a duration.
105         * 
106         * @param start  start of this interval, null means now
107         * @param duration  the duration of this interval, null means zero length
108         * @throws IllegalArgumentException if the end is before the start
109         * @throws ArithmeticException if the end instant exceeds the capacity of a long
110         */
111        public MutableInterval(ReadableInstant start, ReadableDuration duration) {
112            super(start, duration);
113        }
114    
115        /**
116         * Constructs an interval from a millisecond duration and an end instant.
117         * 
118         * @param duration  the duration of this interval, null means zero length
119         * @param end  end of this interval, null means now
120         * @throws IllegalArgumentException if the end is before the start
121         * @throws ArithmeticException if the start instant exceeds the capacity of a long
122         */
123        public MutableInterval(ReadableDuration duration, ReadableInstant end) {
124            super(duration, end);
125        }
126    
127        /**
128         * Constructs an interval from a start instant and a time period.
129         * <p>
130         * When forming the interval, the chronology from the instant is used
131         * if present, otherwise the chronology of the period is used.
132         * 
133         * @param start  start of this interval, null means now
134         * @param period  the period of this interval, null means zero length
135         * @throws IllegalArgumentException if the end is before the start
136         * @throws ArithmeticException if the end instant exceeds the capacity of a long
137         */
138        public MutableInterval(ReadableInstant start, ReadablePeriod period) {
139            super(start, period);
140        }
141    
142        /**
143         * Constructs an interval from a time period and an end instant.
144         * <p>
145         * When forming the interval, the chronology from the instant is used
146         * if present, otherwise the chronology of the period is used.
147         * 
148         * @param period  the period of this interval, null means zero length
149         * @param end  end of this interval, null means now
150         * @throws IllegalArgumentException if the end is before the start
151         * @throws ArithmeticException if the start instant exceeds the capacity of a long
152         */
153        public MutableInterval(ReadablePeriod period, ReadableInstant end) {
154            super(period, end);
155        }
156    
157        /**
158         * Constructs a time interval by converting or copying from another object.
159         * <p>
160         * The recognised object types are defined in
161         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
162         * include ReadableInterval and String.
163         * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
164         * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
165         * 'datetime/period' or 'period/datetime'.
166         * 
167         * @param interval  the time interval to copy
168         * @throws IllegalArgumentException if the interval is invalid
169         */
170        public MutableInterval(Object interval) {
171            super(interval, null);
172        }
173    
174        /**
175         * Constructs a time interval by converting or copying from another object,
176         * overriding the chronology.
177         * <p>
178         * The recognised object types are defined in
179         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
180         * include ReadableInterval and String.
181         * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
182         * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
183         * 'datetime/period' or 'period/datetime'.
184         * 
185         * @param interval  the time interval to copy
186         * @param chronology  the chronology to use, null means ISO default
187         * @throws IllegalArgumentException if the interval is invalid
188         */
189        public MutableInterval(Object interval, Chronology chronology) {
190            super(interval, chronology);
191        }
192    
193        //-----------------------------------------------------------------------
194        /**
195         * Sets this interval from two millisecond instants retaining the chronology.
196         *
197         * @param startInstant  the start of the time interval
198         * @param endInstant  the start of the time interval
199         * @throws IllegalArgumentException if the end is before the start
200         */
201        public void setInterval(long startInstant, long endInstant) {
202            super.setInterval(startInstant, endInstant, getChronology());
203        }
204    
205        /**
206         * Sets this interval to be the same as another.
207         *
208         * @param interval  the interval to copy
209         * @throws IllegalArgumentException if the interval is null
210         */
211        public void setInterval(ReadableInterval interval) {
212            if (interval == null) {
213                throw new IllegalArgumentException("Interval must not be null");
214            }
215            long startMillis = interval.getStartMillis();
216            long endMillis = interval.getEndMillis();
217            Chronology chrono = interval.getChronology();
218            super.setInterval(startMillis, endMillis, chrono);
219        }
220    
221        /**
222         * Sets this interval from two instants, replacing the chronology with
223         * that from the start instant.
224         *
225         * @param start  the start of the time interval
226         * @param end  the start of the time interval
227         * @throws IllegalArgumentException if the end is before the start
228         */
229        public void setInterval(ReadableInstant start, ReadableInstant end) {
230            if (start == null && end == null) {
231                long now = DateTimeUtils.currentTimeMillis();
232                setInterval(now, now);
233            } else {
234                long startMillis = DateTimeUtils.getInstantMillis(start);
235                long endMillis = DateTimeUtils.getInstantMillis(end);
236                Chronology chrono = DateTimeUtils.getInstantChronology(start);
237                super.setInterval(startMillis, endMillis, chrono);
238            }
239        }
240    
241        //-----------------------------------------------------------------------
242        /**
243         * Sets the chronology of this time interval.
244         *
245         * @param chrono  the chronology to use, null means ISO default
246         */
247        public void setChronology(Chronology chrono) {
248            super.setInterval(getStartMillis(), getEndMillis(), chrono);
249        }
250    
251        /**
252         * Sets the start of this time interval.
253         *
254         * @param startInstant  the start of the time interval,
255         *  millisecond instant from 1970-01-01T00:00:00Z
256         * @throws IllegalArgumentException if the end is before the start
257         */
258        public void setStartMillis(long startInstant) {
259            super.setInterval(startInstant, getEndMillis(), getChronology());
260        }
261    
262        /**
263         * Sets the start of this time interval as an Instant.
264         *
265         * @param start  the start of the time interval, null means now
266         * @throws IllegalArgumentException if the end is before the start
267         */
268        public void setStart(ReadableInstant start) {
269            long startMillis = DateTimeUtils.getInstantMillis(start);
270            super.setInterval(startMillis, getEndMillis(), getChronology());
271        }
272    
273        /** 
274         * Sets the end of this time interval.
275         *
276         * @param endInstant  the end of the time interval,
277         *  millisecond instant from 1970-01-01T00:00:00Z
278         * @throws IllegalArgumentException if the end is before the start
279         */
280        public void setEndMillis(long endInstant) {
281            super.setInterval(getStartMillis(), endInstant, getChronology());
282        }
283    
284        /** 
285         * Sets the end of this time interval as an Instant.
286         *
287         * @param end  the end of the time interval, null means now
288         * @throws IllegalArgumentException if the end is before the start
289         */
290        public void setEnd(ReadableInstant end) {
291            long endMillis = DateTimeUtils.getInstantMillis(end);
292            super.setInterval(getStartMillis(), endMillis, getChronology());
293        }
294    
295        //-----------------------------------------------------------------------
296        /**
297         * Sets the duration of this time interval, preserving the start instant.
298         *
299         * @param duration  new duration for interval
300         * @throws IllegalArgumentException if the end is before the start
301         * @throws ArithmeticException if the end instant exceeds the capacity of a long
302         */
303        public void setDurationAfterStart(long duration) {
304            setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration));
305        }
306    
307        /**
308         * Sets the duration of this time interval, preserving the end instant.
309         *
310         * @param duration  new duration for interval
311         * @throws IllegalArgumentException if the end is before the start
312         * @throws ArithmeticException if the start instant exceeds the capacity of a long
313         */
314        public void setDurationBeforeEnd(long duration) {
315            setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration));
316        }
317    
318        //-----------------------------------------------------------------------
319        /**
320         * Sets the duration of this time interval, preserving the start instant.
321         *
322         * @param duration  new duration for interval, null means zero length
323         * @throws IllegalArgumentException if the end is before the start
324         * @throws ArithmeticException if the end instant exceeds the capacity of a long
325         */
326        public void setDurationAfterStart(ReadableDuration duration) {
327            long durationMillis = DateTimeUtils.getDurationMillis(duration);
328            setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis));
329        }
330    
331        /**
332         * Sets the duration of this time interval, preserving the end instant.
333         *
334         * @param duration  new duration for interval, null means zero length
335         * @throws IllegalArgumentException if the end is before the start
336         * @throws ArithmeticException if the start instant exceeds the capacity of a long
337         */
338        public void setDurationBeforeEnd(ReadableDuration duration) {
339            long durationMillis = DateTimeUtils.getDurationMillis(duration);
340            setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis));
341        }
342    
343        //-----------------------------------------------------------------------
344        /**
345         * Sets the period of this time interval, preserving the start instant
346         * and using the ISOChronology in the default zone for calculations.
347         *
348         * @param period  new period for interval, null means zero length
349         * @throws IllegalArgumentException if the end is before the start
350         * @throws ArithmeticException if the end instant exceeds the capacity of a long
351         */
352        public void setPeriodAfterStart(ReadablePeriod period) {
353            if (period == null) {
354                setEndMillis(getStartMillis());
355            } else {
356                setEndMillis(getChronology().add(period, getStartMillis(), 1));
357            }
358        }
359    
360        /**
361         * Sets the period of this time interval, preserving the end instant
362         * and using the ISOChronology in the default zone for calculations.
363         *
364         * @param period  new period for interval, null means zero length
365         * @throws IllegalArgumentException if the end is before the start
366         * @throws ArithmeticException if the start instant exceeds the capacity of a long
367         */
368        public void setPeriodBeforeEnd(ReadablePeriod period) {
369            if (period == null) {
370                setStartMillis(getEndMillis());
371            } else {
372                setStartMillis(getChronology().add(period, getEndMillis(), -1));
373            }
374        }
375    
376        //-----------------------------------------------------------------------
377        /**
378         * Clone this object without having to cast the returned object.
379         *
380         * @return a clone of the this object.
381         */
382        public MutableInterval copy() {
383            return (MutableInterval) clone();
384        }
385    
386        /**
387         * Clone this object.
388         *
389         * @return a clone of this object.
390         */
391        public Object clone() {
392            try {
393                return super.clone();
394            } catch (CloneNotSupportedException ex) {
395                throw new InternalError("Clone error");
396            }
397        }
398    
399    }