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 */
016package org.joda.time;
017
018import java.io.Serializable;
019
020import org.joda.time.base.BaseInterval;
021import org.joda.time.field.FieldUtils;
022import org.joda.time.format.ISODateTimeFormat;
023import 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 */
052public 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}