001/*
002 *  Copyright 2001-2006 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.chrono.ISOChronology;
022import org.joda.time.format.ISODateTimeFormat;
023import org.joda.time.format.ISOPeriodFormat;
024
025/**
026 * Interval is the standard implementation of an immutable 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 * Interval is thread-safe and immutable.
043 *
044 * @author Brian S O'Neill
045 * @author Sean Geoghegan
046 * @author Stephen Colebourne
047 * @author Julen Parra
048 * @since 1.0
049 */
050public final class Interval
051        extends BaseInterval
052        implements ReadableInterval, Serializable {
053
054    /** Serialization version */
055    private static final long serialVersionUID = 4922451897541386752L;
056
057    //-----------------------------------------------------------------------
058    /**
059     * Parses a {@code Interval} from the specified string.
060     * <p>
061     * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
062     * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
063     * 'datetime/period' or 'period/datetime'.
064     * 
065     * @param str  the string to parse, not null
066     * @since 2.0
067     */
068    public static Interval parse(String str) {
069        return new Interval(str);
070    }
071
072    //-----------------------------------------------------------------------
073    /**
074     * Constructs an interval from a start and end instant with the ISO
075     * default chronology in the default time zone.
076     * 
077     * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
078     * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
079     * @throws IllegalArgumentException if the end is before the start
080     */
081    public Interval(long startInstant, long endInstant) {
082        super(startInstant, endInstant, null);
083    }
084
085    /**
086     * Constructs an interval from a start and end instant with the ISO
087     * default chronology in the specified time zone.
088     * 
089     * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
090     * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
091     * @param zone  the time zone to use, null means default zone
092     * @throws IllegalArgumentException if the end is before the start
093     * @since 1.5
094     */
095    public Interval(long startInstant, long endInstant, DateTimeZone zone) {
096        super(startInstant, endInstant, ISOChronology.getInstance(zone));
097    }
098
099    /**
100     * Constructs an interval from a start and end instant with the
101     * specified chronology.
102     * 
103     * @param chronology  the chronology to use, null is ISO default
104     * @param startInstant  start of this interval, as milliseconds from 1970-01-01T00:00:00Z.
105     * @param endInstant  end of this interval, as milliseconds from 1970-01-01T00:00:00Z.
106     * @throws IllegalArgumentException if the end is before the start
107     */
108    public Interval(long startInstant, long endInstant, Chronology chronology) {
109        super(startInstant, endInstant, chronology);
110    }
111
112    /**
113     * Constructs an interval from a start and end instant.
114     * <p>
115     * The chronology used is that of the start instant.
116     * 
117     * @param start  start of this interval, null means now
118     * @param end  end of this interval, null means now
119     * @throws IllegalArgumentException if the end is before the start
120     */
121    public Interval(ReadableInstant start, ReadableInstant end) {
122        super(start, end);
123    }
124
125    /**
126     * Constructs an interval from a start instant and a duration.
127     * 
128     * @param start  start of this interval, null means now
129     * @param duration  the duration of this interval, null means zero length
130     * @throws IllegalArgumentException if the end is before the start
131     * @throws ArithmeticException if the end instant exceeds the capacity of a long
132     */
133    public Interval(ReadableInstant start, ReadableDuration duration) {
134        super(start, duration);
135    }
136
137    /**
138     * Constructs an interval from a millisecond duration and an end instant.
139     * 
140     * @param duration  the duration of this interval, null means zero length
141     * @param end  end of this interval, null means now
142     * @throws IllegalArgumentException if the end is before the start
143     * @throws ArithmeticException if the start instant exceeds the capacity of a long
144     */
145    public Interval(ReadableDuration duration, ReadableInstant end) {
146        super(duration, end);
147    }
148
149    /**
150     * Constructs an interval from a start instant and a time period.
151     * <p>
152     * When forming the interval, the chronology from the instant is used
153     * if present, otherwise the chronology of the period is used.
154     * 
155     * @param start  start of this interval, null means now
156     * @param period  the period of this interval, null means zero length
157     * @throws IllegalArgumentException if the end is before the start
158     * @throws ArithmeticException if the end instant exceeds the capacity of a long
159     */
160    public Interval(ReadableInstant start, ReadablePeriod period) {
161        super(start, period);
162    }
163
164    /**
165     * Constructs an interval from a time period and an end instant.
166     * <p>
167     * When forming the interval, the chronology from the instant is used
168     * if present, otherwise the chronology of the period is used.
169     * 
170     * @param period  the period of this interval, null means zero length
171     * @param end  end of this interval, null means now
172     * @throws IllegalArgumentException if the end is before the start
173     * @throws ArithmeticException if the start instant exceeds the capacity of a long
174     */
175    public Interval(ReadablePeriod period, ReadableInstant end) {
176        super(period, end);
177    }
178
179    /**
180     * Constructs a time interval by converting or copying from another object.
181     * <p>
182     * The recognised object types are defined in
183     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
184     * include ReadableInterval and String.
185     * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
186     * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
187     * 'datetime/period' or 'period/datetime'.
188     * 
189     * @param interval  the time interval to copy
190     * @throws IllegalArgumentException if the interval is invalid
191     */
192    public Interval(Object interval) {
193        super(interval, null);
194    }
195
196    /**
197     * Constructs a time interval by converting or copying from another object,
198     * overriding the chronology.
199     * <p>
200     * The recognised object types are defined in
201     * {@link org.joda.time.convert.ConverterManager ConverterManager} and
202     * include ReadableInterval and String.
203     * The String formats are described by {@link ISODateTimeFormat#dateTimeParser()}
204     * and {@link ISOPeriodFormat#standard()}, and may be 'datetime/datetime',
205     * 'datetime/period' or 'period/datetime'.
206     * 
207     * @param interval  the time interval to copy
208     * @param chronology  the chronology to use, null means ISO default
209     * @throws IllegalArgumentException if the interval is invalid
210     */
211    public Interval(Object interval, Chronology chronology) {
212        super(interval, chronology);
213    }
214
215    //-----------------------------------------------------------------------
216    /**
217     * Get this interval as an immutable <code>Interval</code> object
218     * by returning <code>this</code>.
219     *
220     * @return <code>this</code>
221     */
222    public Interval toInterval() {
223        return this;
224    }
225
226    //-----------------------------------------------------------------------
227    /**
228     * Gets the overlap between this interval and another interval.
229     * <p>
230     * Intervals are inclusive of the start instant and exclusive of the end.
231     * An interval overlaps another if it shares some common part of the
232     * datetime continuum. This method returns the amount of the overlap,
233     * only if the intervals actually do overlap.
234     * If the intervals do not overlap, then null is returned.
235     * <p>
236     * When two intervals are compared the result is one of three states:
237     * (a) they abut, (b) there is a gap between them, (c) they overlap.
238     * The abuts state takes precedence over the other two, thus a zero duration
239     * interval at the start of a larger interval abuts and does not overlap.
240     * <p>
241     * The chronology of the returned interval is the same as that of
242     * this interval (the chronology of the interval parameter is not used).
243     * Note that the use of the chronology was only correctly implemented
244     * in version 1.3.
245     *
246     * @param interval  the interval to examine, null means now
247     * @return the overlap interval, null if no overlap
248     * @since 1.1
249     */
250    public Interval overlap(ReadableInterval interval) {
251        interval = DateTimeUtils.getReadableInterval(interval);
252        if (overlaps(interval) == false) {
253            return null;
254        }
255        long start = Math.max(getStartMillis(), interval.getStartMillis());
256        long end = Math.min(getEndMillis(), interval.getEndMillis());
257        return new Interval(start, end, getChronology());
258    }
259
260    //-----------------------------------------------------------------------
261    /**
262     * Gets the gap between this interval and another interval.
263     * The other interval can be either before or after this interval.
264     * <p>
265     * Intervals are inclusive of the start instant and exclusive of the end.
266     * An interval has a gap to another interval if there is a non-zero
267     * duration between them. This method returns the amount of the gap only
268     * if the intervals do actually have a gap between them.
269     * If the intervals overlap or abut, then null is returned.
270     * <p>
271     * When two intervals are compared the result is one of three states:
272     * (a) they abut, (b) there is a gap between them, (c) they overlap.
273     * The abuts state takes precedence over the other two, thus a zero duration
274     * interval at the start of a larger interval abuts and does not overlap.
275     * <p>
276     * The chronology of the returned interval is the same as that of
277     * this interval (the chronology of the interval parameter is not used).
278     * Note that the use of the chronology was only correctly implemented
279     * in version 1.3.
280     *
281     * @param interval  the interval to examine, null means now
282     * @return the gap interval, null if no gap
283     * @since 1.1
284     */
285    public Interval gap(ReadableInterval interval) {
286        interval = DateTimeUtils.getReadableInterval(interval);
287        long otherStart = interval.getStartMillis();
288        long otherEnd = interval.getEndMillis();
289        long thisStart = getStartMillis();
290        long thisEnd = getEndMillis();
291        if (thisStart > otherEnd) {
292            return new Interval(otherEnd, thisStart, getChronology());
293        } else if (otherStart > thisEnd) {
294            return new Interval(thisEnd, otherStart, getChronology());
295        } else {
296            return null;
297        }
298    }
299
300    //-----------------------------------------------------------------------
301    /**
302     * Does this interval abut with the interval specified.
303     * <p>
304     * Intervals are inclusive of the start instant and exclusive of the end.
305     * An interval abuts if it starts immediately after, or ends immediately
306     * before this interval without overlap.
307     * A zero duration interval abuts with itself.
308     * <p>
309     * When two intervals are compared the result is one of three states:
310     * (a) they abut, (b) there is a gap between them, (c) they overlap.
311     * The abuts state takes precedence over the other two, thus a zero duration
312     * interval at the start of a larger interval abuts and does not overlap.
313     * <p>
314     * For example:
315     * <pre>
316     * [09:00 to 10:00) abuts [08:00 to 08:30)  = false (completely before)
317     * [09:00 to 10:00) abuts [08:00 to 09:00)  = true
318     * [09:00 to 10:00) abuts [08:00 to 09:01)  = false (overlaps)
319     * 
320     * [09:00 to 10:00) abuts [09:00 to 09:00)  = true
321     * [09:00 to 10:00) abuts [09:00 to 09:01)  = false (overlaps)
322     * 
323     * [09:00 to 10:00) abuts [10:00 to 10:00)  = true
324     * [09:00 to 10:00) abuts [10:00 to 10:30)  = true
325     * 
326     * [09:00 to 10:00) abuts [10:30 to 11:00)  = false (completely after)
327     * 
328     * [14:00 to 14:00) abuts [14:00 to 14:00)  = true
329     * [14:00 to 14:00) abuts [14:00 to 15:00)  = true
330     * [14:00 to 14:00) abuts [13:00 to 14:00)  = true
331     * </pre>
332     *
333     * @param interval  the interval to examine, null means now
334     * @return true if the interval abuts
335     * @since 1.1
336     */
337    public boolean abuts(ReadableInterval interval) {
338        if (interval == null) {
339            long now = DateTimeUtils.currentTimeMillis();
340            return (getStartMillis() == now || getEndMillis() == now);
341        } else {
342            return (interval.getEndMillis() == getStartMillis() ||
343                    getEndMillis() == interval.getStartMillis());
344        }
345    }
346
347    //-----------------------------------------------------------------------
348    /**
349     * Creates a new interval with the same start and end, but a different chronology.
350     *
351     * @param chronology  the chronology to use, null means ISO default
352     * @return an interval with a different chronology
353     */
354    public Interval withChronology(Chronology chronology) {
355        if (getChronology() == chronology) {
356            return this;
357        }
358        return new Interval(getStartMillis(), getEndMillis(), chronology);
359    }
360
361    /**
362     * Creates a new interval with the specified start millisecond instant.
363     *
364     * @param startInstant  the start instant for the new interval
365     * @return an interval with the end from this interval and the specified start
366     * @throws IllegalArgumentException if the resulting interval has end before start
367     */
368    public Interval withStartMillis(long startInstant) {
369        if (startInstant == getStartMillis()) {
370            return this;
371        }
372        return new Interval(startInstant, getEndMillis(), getChronology());
373    }
374
375    /**
376     * Creates a new interval with the specified start instant.
377     *
378     * @param start  the start instant for the new interval, null means now
379     * @return an interval with the end from this interval and the specified start
380     * @throws IllegalArgumentException if the resulting interval has end before start
381     */
382    public Interval withStart(ReadableInstant start) {
383        long startMillis = DateTimeUtils.getInstantMillis(start);
384        return withStartMillis(startMillis);
385    }
386
387    /**
388     * Creates a new interval with the specified start millisecond instant.
389     *
390     * @param endInstant  the end instant for the new interval
391     * @return an interval with the start from this interval and the specified end
392     * @throws IllegalArgumentException if the resulting interval has end before start
393     */
394    public Interval withEndMillis(long endInstant) {
395        if (endInstant == getEndMillis()) {
396            return this;
397        }
398        return new Interval(getStartMillis(), endInstant, getChronology());
399    }
400
401    /**
402     * Creates a new interval with the specified end instant.
403     *
404     * @param end  the end instant for the new interval, null means now
405     * @return an interval with the start from this interval and the specified end
406     * @throws IllegalArgumentException if the resulting interval has end before start
407     */
408    public Interval withEnd(ReadableInstant end) {
409        long endMillis = DateTimeUtils.getInstantMillis(end);
410        return withEndMillis(endMillis);
411    }
412
413    //-----------------------------------------------------------------------
414    /**
415     * Creates a new interval with the specified duration after the start instant.
416     *
417     * @param duration  the duration to add to the start to get the new end instant, null means zero
418     * @return an interval with the start from this interval and a calculated end
419     * @throws IllegalArgumentException if the duration is negative
420     */
421    public Interval withDurationAfterStart(ReadableDuration duration) {
422        long durationMillis = DateTimeUtils.getDurationMillis(duration);
423        if (durationMillis == toDurationMillis()) {
424            return this;
425        }
426        Chronology chrono = getChronology();
427        long startMillis = getStartMillis();
428        long endMillis = chrono.add(startMillis, durationMillis, 1);
429        return new Interval(startMillis, endMillis, chrono);
430    }
431
432    /**
433     * Creates a new interval with the specified duration before the end instant.
434     *
435     * @param duration  the duration to add to the start to get the new end instant, null means zero
436     * @return an interval with the start from this interval and a calculated end
437     * @throws IllegalArgumentException if the duration is negative
438     */
439    public Interval withDurationBeforeEnd(ReadableDuration duration) {
440        long durationMillis = DateTimeUtils.getDurationMillis(duration);
441        if (durationMillis == toDurationMillis()) {
442            return this;
443        }
444        Chronology chrono = getChronology();
445        long endMillis = getEndMillis();
446        long startMillis = chrono.add(endMillis, durationMillis, -1);
447        return new Interval(startMillis, endMillis, chrono);
448    }
449
450    //-----------------------------------------------------------------------
451    /**
452     * Creates a new interval with the specified period after the start instant.
453     *
454     * @param period  the period to add to the start to get the new end instant, null means zero
455     * @return an interval with the start from this interval and a calculated end
456     * @throws IllegalArgumentException if the period is negative
457     */
458    public Interval withPeriodAfterStart(ReadablePeriod period) {
459        if (period == null) {
460            return withDurationAfterStart(null);
461        }
462        Chronology chrono = getChronology();
463        long startMillis = getStartMillis();
464        long endMillis = chrono.add(period, startMillis, 1);
465        return new Interval(startMillis, endMillis, chrono);
466    }
467
468    /**
469     * Creates a new interval with the specified period before the end instant.
470     *
471     * @param period  the period to add to the start to get the new end instant, null means zero
472     * @return an interval with the start from this interval and a calculated end
473     * @throws IllegalArgumentException if the period is negative
474     */
475    public Interval withPeriodBeforeEnd(ReadablePeriod period) {
476        if (period == null) {
477            return withDurationBeforeEnd(null);
478        }
479        Chronology chrono = getChronology();
480        long endMillis = getEndMillis();
481        long startMillis = chrono.add(period, endMillis, -1);
482        return new Interval(startMillis, endMillis, chrono);
483    }
484
485}