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         * Parses a {@code MutableInterval} from the specified string.
062         * <p>
063         * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
064         * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
065         * 'datetime/period' or 'period/datetime'.
066         * 
067         * @param str  the string to parse, not null
068         * @since 2.0
069         */
070        public static MutableInterval parse(String str) {
071            return new MutableInterval(str);
072        }
073    
074        //-----------------------------------------------------------------------
075        /**
076         * Constructs a zero length time interval from 1970-01-01 to 1970-01-01.
077         */
078        public MutableInterval() {
079            super(0L, 0L, null);
080        }
081    
082        /**
083         * Constructs an interval from a start and end instant with the ISO default chronology.
084         * 
085         * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
086         * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
087         * @throws IllegalArgumentException if the end is before the start
088         */
089        public MutableInterval(long startInstant, long endInstant) {
090            super(startInstant, endInstant, null);
091        }
092    
093        /**
094         * Constructs an interval from a start and end instant with a chronology.
095         * 
096         * @param chronology  the chronology to use, null is ISO default
097         * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
098         * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
099         * @throws IllegalArgumentException if the end is before the start
100         */
101        public MutableInterval(long startInstant, long endInstant, Chronology chronology) {
102            super(startInstant, endInstant, chronology);
103        }
104    
105        /**
106         * Constructs an interval from a start and end instant.
107         * <p>
108         * The chronology used is that of the start instant.
109         * 
110         * @param start  start of this interval, null means now
111         * @param end  end of this interval, null means now
112         * @throws IllegalArgumentException if the end is before the start
113         */
114        public MutableInterval(ReadableInstant start, ReadableInstant end) {
115            super(start, end);
116        }
117    
118        /**
119         * Constructs an interval from a start instant and a duration.
120         * 
121         * @param start  start of this interval, null means now
122         * @param duration  the duration of this interval, null means zero length
123         * @throws IllegalArgumentException if the end is before the start
124         * @throws ArithmeticException if the end instant exceeds the capacity of a long
125         */
126        public MutableInterval(ReadableInstant start, ReadableDuration duration) {
127            super(start, duration);
128        }
129    
130        /**
131         * Constructs an interval from a millisecond duration and an end instant.
132         * 
133         * @param duration  the duration of this interval, null means zero length
134         * @param end  end of this interval, null means now
135         * @throws IllegalArgumentException if the end is before the start
136         * @throws ArithmeticException if the start instant exceeds the capacity of a long
137         */
138        public MutableInterval(ReadableDuration duration, ReadableInstant end) {
139            super(duration, end);
140        }
141    
142        /**
143         * Constructs an interval from a start instant and a time period.
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 start  start of this interval, null means now
149         * @param period  the period of this interval, null means zero length
150         * @throws IllegalArgumentException if the end is before the start
151         * @throws ArithmeticException if the end instant exceeds the capacity of a long
152         */
153        public MutableInterval(ReadableInstant start, ReadablePeriod period) {
154            super(start, period);
155        }
156    
157        /**
158         * Constructs an interval from a time period and an end instant.
159         * <p>
160         * When forming the interval, the chronology from the instant is used
161         * if present, otherwise the chronology of the period is used.
162         * 
163         * @param period  the period of this interval, null means zero length
164         * @param end  end of this interval, null means now
165         * @throws IllegalArgumentException if the end is before the start
166         * @throws ArithmeticException if the start instant exceeds the capacity of a long
167         */
168        public MutableInterval(ReadablePeriod period, ReadableInstant end) {
169            super(period, end);
170        }
171    
172        /**
173         * Constructs a time interval by converting or copying from another object.
174         * <p>
175         * The recognised object types are defined in
176         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
177         * include ReadableInterval and String.
178         * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
179         * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
180         * 'datetime/period' or 'period/datetime'.
181         * 
182         * @param interval  the time interval to copy
183         * @throws IllegalArgumentException if the interval is invalid
184         */
185        public MutableInterval(Object interval) {
186            super(interval, null);
187        }
188    
189        /**
190         * Constructs a time interval by converting or copying from another object,
191         * overriding the chronology.
192         * <p>
193         * The recognised object types are defined in
194         * {@link org.joda.time.convert.ConverterManager ConverterManager} and
195         * include ReadableInterval and String.
196         * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
197         * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
198         * 'datetime/period' or 'period/datetime'.
199         * 
200         * @param interval  the time interval to copy
201         * @param chronology  the chronology to use, null means ISO default
202         * @throws IllegalArgumentException if the interval is invalid
203         */
204        public MutableInterval(Object interval, Chronology chronology) {
205            super(interval, chronology);
206        }
207    
208        //-----------------------------------------------------------------------
209        /**
210         * Sets this interval from two millisecond instants retaining the chronology.
211         *
212         * @param startInstant  the start of the time interval
213         * @param endInstant  the start of the time interval
214         * @throws IllegalArgumentException if the end is before the start
215         */
216        public void setInterval(long startInstant, long endInstant) {
217            super.setInterval(startInstant, endInstant, getChronology());
218        }
219    
220        /**
221         * Sets this interval to be the same as another.
222         *
223         * @param interval  the interval to copy
224         * @throws IllegalArgumentException if the interval is null
225         */
226        public void setInterval(ReadableInterval interval) {
227            if (interval == null) {
228                throw new IllegalArgumentException("Interval must not be null");
229            }
230            long startMillis = interval.getStartMillis();
231            long endMillis = interval.getEndMillis();
232            Chronology chrono = interval.getChronology();
233            super.setInterval(startMillis, endMillis, chrono);
234        }
235    
236        /**
237         * Sets this interval from two instants, replacing the chronology with
238         * that from the start instant.
239         *
240         * @param start  the start of the time interval
241         * @param end  the start of the time interval
242         * @throws IllegalArgumentException if the end is before the start
243         */
244        public void setInterval(ReadableInstant start, ReadableInstant end) {
245            if (start == null && end == null) {
246                long now = DateTimeUtils.currentTimeMillis();
247                setInterval(now, now);
248            } else {
249                long startMillis = DateTimeUtils.getInstantMillis(start);
250                long endMillis = DateTimeUtils.getInstantMillis(end);
251                Chronology chrono = DateTimeUtils.getInstantChronology(start);
252                super.setInterval(startMillis, endMillis, chrono);
253            }
254        }
255    
256        //-----------------------------------------------------------------------
257        /**
258         * Sets the chronology of this time interval.
259         *
260         * @param chrono  the chronology to use, null means ISO default
261         */
262        public void setChronology(Chronology chrono) {
263            super.setInterval(getStartMillis(), getEndMillis(), chrono);
264        }
265    
266        /**
267         * Sets the start of this time interval.
268         *
269         * @param startInstant  the start of the time interval,
270         *  millisecond instant from 1970-01-01T00:00:00Z
271         * @throws IllegalArgumentException if the end is before the start
272         */
273        public void setStartMillis(long startInstant) {
274            super.setInterval(startInstant, getEndMillis(), getChronology());
275        }
276    
277        /**
278         * Sets the start of this time interval as an Instant.
279         *
280         * @param start  the start of the time interval, null means now
281         * @throws IllegalArgumentException if the end is before the start
282         */
283        public void setStart(ReadableInstant start) {
284            long startMillis = DateTimeUtils.getInstantMillis(start);
285            super.setInterval(startMillis, getEndMillis(), getChronology());
286        }
287    
288        /** 
289         * Sets the end of this time interval.
290         *
291         * @param endInstant  the end of the time interval,
292         *  millisecond instant from 1970-01-01T00:00:00Z
293         * @throws IllegalArgumentException if the end is before the start
294         */
295        public void setEndMillis(long endInstant) {
296            super.setInterval(getStartMillis(), endInstant, getChronology());
297        }
298    
299        /** 
300         * Sets the end of this time interval as an Instant.
301         *
302         * @param end  the end of the time interval, null means now
303         * @throws IllegalArgumentException if the end is before the start
304         */
305        public void setEnd(ReadableInstant end) {
306            long endMillis = DateTimeUtils.getInstantMillis(end);
307            super.setInterval(getStartMillis(), endMillis, getChronology());
308        }
309    
310        //-----------------------------------------------------------------------
311        /**
312         * Sets the duration of this time interval, preserving the start instant.
313         *
314         * @param duration  new duration for interval
315         * @throws IllegalArgumentException if the end is before the start
316         * @throws ArithmeticException if the end instant exceeds the capacity of a long
317         */
318        public void setDurationAfterStart(long duration) {
319            setEndMillis(FieldUtils.safeAdd(getStartMillis(), duration));
320        }
321    
322        /**
323         * Sets the duration of this time interval, preserving the end instant.
324         *
325         * @param duration  new duration for interval
326         * @throws IllegalArgumentException if the end is before the start
327         * @throws ArithmeticException if the start instant exceeds the capacity of a long
328         */
329        public void setDurationBeforeEnd(long duration) {
330            setStartMillis(FieldUtils.safeAdd(getEndMillis(), -duration));
331        }
332    
333        //-----------------------------------------------------------------------
334        /**
335         * Sets the duration of this time interval, preserving the start instant.
336         *
337         * @param duration  new duration for interval, null means zero length
338         * @throws IllegalArgumentException if the end is before the start
339         * @throws ArithmeticException if the end instant exceeds the capacity of a long
340         */
341        public void setDurationAfterStart(ReadableDuration duration) {
342            long durationMillis = DateTimeUtils.getDurationMillis(duration);
343            setEndMillis(FieldUtils.safeAdd(getStartMillis(), durationMillis));
344        }
345    
346        /**
347         * Sets the duration of this time interval, preserving the end instant.
348         *
349         * @param duration  new duration for interval, null means zero length
350         * @throws IllegalArgumentException if the end is before the start
351         * @throws ArithmeticException if the start instant exceeds the capacity of a long
352         */
353        public void setDurationBeforeEnd(ReadableDuration duration) {
354            long durationMillis = DateTimeUtils.getDurationMillis(duration);
355            setStartMillis(FieldUtils.safeAdd(getEndMillis(), -durationMillis));
356        }
357    
358        //-----------------------------------------------------------------------
359        /**
360         * Sets the period of this time interval, preserving the start instant
361         * and using the ISOChronology in the default zone for calculations.
362         *
363         * @param period  new period for interval, null means zero length
364         * @throws IllegalArgumentException if the end is before the start
365         * @throws ArithmeticException if the end instant exceeds the capacity of a long
366         */
367        public void setPeriodAfterStart(ReadablePeriod period) {
368            if (period == null) {
369                setEndMillis(getStartMillis());
370            } else {
371                setEndMillis(getChronology().add(period, getStartMillis(), 1));
372            }
373        }
374    
375        /**
376         * Sets the period of this time interval, preserving the end instant
377         * and using the ISOChronology in the default zone for calculations.
378         *
379         * @param period  new period for interval, null means zero length
380         * @throws IllegalArgumentException if the end is before the start
381         * @throws ArithmeticException if the start instant exceeds the capacity of a long
382         */
383        public void setPeriodBeforeEnd(ReadablePeriod period) {
384            if (period == null) {
385                setStartMillis(getEndMillis());
386            } else {
387                setStartMillis(getChronology().add(period, getEndMillis(), -1));
388            }
389        }
390    
391        //-----------------------------------------------------------------------
392        /**
393         * Clone this object without having to cast the returned object.
394         *
395         * @return a clone of the this object.
396         */
397        public MutableInterval copy() {
398            return (MutableInterval) clone();
399        }
400    
401        /**
402         * Clone this object.
403         *
404         * @return a clone of this object.
405         */
406        public Object clone() {
407            try {
408                return super.clone();
409            } catch (CloneNotSupportedException ex) {
410                throw new InternalError("Clone error");
411            }
412        }
413    
414    }